TypeScript中如何在函数参数使用typeof并实现正确协变?
TypeScript按类过滤实例列表的问题解决
问题1:替代typeof T的写法
TypeScript不支持在泛型参数中直接使用typeof T指代类的构造函数类型。正确的做法是显式定义构造函数类型:new (...args: any[]) => T,它表示任何能生成T实例的构造函数,兼容任意参数列表。
问题2:实现协变支持
TypeScript没有out关键字,但若泛型参数T仅作为返回值类型(或只读位置)出现,编译器会自动启用协变。我们需要确保构造函数类型的定义不限制协变:使用new (...args: any[]) => T既适配带参数的构造函数,又让T保持协变能力。
完整可运行代码
class A { } class B extends A { constructor(pb: any) { super(); } } class C extends A { constructor(pc: any) { super(); } } function filterByClass<T extends A>(cls: new (...args: any[]) => T, list: A[]): T[] { // 添加类型守卫,让编译器识别过滤后的数组类型 return list.filter((item): item is T => item instanceof cls); } // 使用示例 const a = new A(); const b = new B(1); const c = new C(1); const arr = [a, b, c]; const arrB = filterByClass(B, arr); // 类型推断为B[] const arrC = filterByClass(C, arr); // 类型推断为C[]
关键细节
- 类型守卫:
item is T断言让filter的返回类型从A[]精确为T[],避免类型丢失。 - 构造函数兼容性:
(...args: any[])接受任意参数,解决了带参数构造函数的类型不匹配问题。 - 协变验证:可以传入
A的子类构造函数,返回对应子类数组;传入A构造函数则返回A[],完全符合协变预期。
内容的提问来源于stack exchange,提问作者Tom HANAX
相关产品推荐
相关产品推荐

