如何让TypeScript函数接收任意泛型参数的Foo类型数组?
问题:实现可接收任意泛型参数Foo实例数组的process函数
用户代码如下:
type Foo<T = unknown> = { bar: T bar2: (v: T) => T } const f1 : Foo<number> = { bar: 42, bar2: (v: number) => 5 + v } const f2 : Foo<string> = { bar: "hello", bar2: (v: string) => v } // 意图:接收任意Foo实例或string的数组 function process(arr: (Foo|string)[]) { ... } process([f1, f2]) // 报错
运行时出现的错误:
Type 'Foo<number>' is not assignable to type 'string | Foo<unknown>'. Type 'Foo<number>' is not assignable to type 'Foo<unknown>'. Types of property 'bar2' are incompatible. Type '(v: number) => number' is not assignable to type '(v: unknown) => unknown'. Types of parameters 'v' and 'v' are incompatible. Type 'unknown' is not assignable to type 'number'
错误原因
TypeScript中函数参数遵循逆变规则:如果类型A是类型B的子类型,那么(B) => any是(A) => any的子类型。这里Foo<unknown>的bar2要求参数是unknown(可接受任意类型),而Foo<number>的bar2只接受number类型。如果把Foo<number>当作Foo<unknown>使用,调用bar2时可能传入非number值,会导致运行时错误,因此TypeScript禁止这种赋值。
解决方案
方案1:使用any兼容任意Foo
通过Foo<any>绕过类型检查,any可以兼容所有泛型参数的Foo实例:
function process(arr: (Foo<any> | string)[]) { // 函数逻辑 } process([f1, f2]) // 正常运行
注意:any会关闭类型检查,若在process内部错误调用bar2传错参数,无法得到编译期提示。
方案2:泛型函数+联合类型
将process定义为泛型函数,指定泛型参数为所有Foo实例的泛型参数联合类型:
function process<T extends unknown>(arr: Array<Foo<T> | string>) { // 可通过类型守卫处理不同类型的元素 arr.forEach(item => { if ('bar' in item) { // item 类型为 Foo<T> console.log(item.bar); } else { // item 类型为 string console.log(item); } }); } // 调用时手动指定联合类型 process<number | string>([f1, f2])
方案3:类型断言(不推荐)
在调用时将Foo<number>和Foo<string>断言为Foo<unknown>,强制通过类型检查:
function process(arr: (Foo<unknown> | string)[]) { // 函数逻辑 } process([f1 as Foo<unknown>, f2 as Foo<unknown>])
此方法会丢失类型安全性,仅在确定process内部不会错误调用bar2时使用。
内容的提问来源于stack exchange,提问作者Guid
相关产品推荐
相关产品推荐

