TypeScript泛型参数类型推断不符合预期问题求助
TypeScript泛型类型推断异常问题解决
问题现象
示例1:正常推断
当直接使用T[]作为参数类型时,TypeScript能自动将数组中所有元素的类型合并为联合类型:
declare function foo<T>(arg: T[]): void; foo([1, "a", new Date()]); // 正确推断为foo<number|string|Date>(...)
示例2:推断异常
但当参数类型为I<T>[](I是包含T的对象类型)时,TypeScript会错误地将泛型T窄化为第一个元素的类型,导致后续元素类型不匹配报错:
type I<T> = { x: T }; declare function foo<T>(arg: I<T>[]): void; foo([{x: 1}, {x: "a"}]); // 报错:string类型无法赋值给number类型,此时T被推断为number
手动指定泛型参数foo<number|string>([{x: 1}, {x: "a"}])可以正常运行,但需要实现无需显式指定的自动推断。尝试修改函数返回值为T也无法解决问题:
type I<T> = { x: T }; declare function foo<T>(arg: I<T>[]): T; const res: number|string = foo([{x: 1}, {x: "a"}]); // 仍报相同错误
解决方案
方案1:使用readonly修饰数组参数
将数组参数类型改为readonly I<T>[],TypeScript会调整推断逻辑,自动将所有元素的x属性类型合并为联合类型:
type I<T> = { x: T }; declare function foo<T>(arg: readonly I<T>[]): void; foo([{x: 1}, {x: "a"}]); // 正确推断为foo<number|string>(...)
方案2:使用可变参数泛型提取联合类型
通过可变参数泛型接收数组元素的具体类型,再提取所有x属性的联合类型:
type I<T> = { x: T }; // 泛型T为元组类型,每个元素对应数组中元素的x类型 declare function foo<T extends unknown[]>(arg: { [K in keyof T]: I<T[K]> }): void; foo([{x: 1}, {x: "a"}]); // T被推断为[number, string],若需直接使用联合类型可通过T[number]获取
方案3:使用条件类型强制推断联合类型
通过infer关键字提取数组元素中x属性的类型,自动合并为联合类型:
type I<T> = { x: T }; type ExtractXType<T> = T extends I<infer U> ? U : never; declare function foo<T extends I<any>[]>(arg: T): ExtractXType<T[number]>; const res = foo([{x: 1}, {x: "a"}]); // res类型自动推断为number|string
原理说明
TypeScript默认对I<T>[]这类结构化泛型数组的推断逻辑是:优先尝试找到一个单一类型的T,使得所有数组元素都符合I<T>。当遇到第一个元素的x为number时,会先锁定T=number,导致后续string类型的元素不匹配。
使用readonly或可变参数泛型可以改变推断逻辑,让TypeScript优先考虑联合类型的可能性,从而自动合并所有元素的类型。
内容的提问来源于stack exchange,提问作者Yevgeniy P
相关产品推荐
相关产品推荐

