TypeScript泛型数组索引访问无法实现instanceof类型收窄问题咨询
TypeScript泛型数组索引访问时instanceof无法收窄类型的原因
这本质是TypeScript泛型类型系统的设计限制导致的:
泛型数组的整体类型约束
在泛型函数printInfo<T extends A>中,参数obj被定义为T[],意味着整个数组的元素类型被绑定到泛型T(T是A的子类型)。当直接通过obj[i]访问元素时,TypeScript会将其类型锁定为T——哪怕你用instanceof B检查出当前元素是B的实例,TypeScript也无法修改T的泛型约束,因为T代表的是数组所有元素的共同类型,它可能并不包含B的专属属性(比如age),所以直接访问obj[i].age会触发类型检查错误。临时变量与forEach参数的局部类型收窄
当你把obj[i]赋值给临时变量tmp,或者在forEach中拿到单个元素it时,这些变量是当前元素的独立引用。此时instanceof B的检查会将变量的类型收窄为T & B(即同时满足泛型T和B的类型交集),这个交集类型必然包含B的所有属性,因此访问tmp.age或it.age时不会报错。
举个实际场景的例子:如果调用printInfo时传入的是A[]类型的数组(此时T = A),数组中可以混合A、B、C的实例。TypeScript在泛型函数内部无法提前知晓T的具体类型,所以基于T的约束(A),它会认为obj[i]没有age或desc属性;而临时变量和forEach参数的类型收窄是针对单个元素的具体类型,不受数组整体泛型约束的限制,因此能正确识别子类属性。
示例代码:
class A { name: string constructor(name: string){this.name = name} } class B extends A{ age: number constructor(name: string, age: number){ super(name) this.age = age }; } class C extends A{ desc: string constructor(name: string, desc: string){ super(name) this.desc = desc }; } function printInfo<T extends A>(obj: T[]){ for(let i = 0; i < obj.length; i++){ if(obj[i] instanceof B){ console.log('age: ' + obj[i].age) // error: Property 'age' does not exist on type 'T'. } if(obj[i] instanceof C){ console.log('desc: ' + (obj[i].desc)) // error: Property 'desc' does not exist on type 'T'. } } for(let i = 0; i < obj.length; i++){ const tmp = obj[i] if(tmp instanceof B){ console.log('age: ' + tmp.age) // okay } if(tmp instanceof C){ console.log('desc: ' + (tmp.desc)) // okay } } obj.forEach((it:T) => { console.log('name: ' + it.name) if(it instanceof B){ console.log('age: ' + it.age) // okay } if(it instanceof C){ console.log('desc: ' + it.desc) // okay } } ) }
内容的提问来源于stack exchange,提问作者snow falling
相关产品推荐
相关产品推荐

