TypeScript动态筛选类实例的类型推导问题
解决TypeScript中getInstance函数的类型推导问题
问题背景
现有类A、B及对应的类型谓词函数isA、isB,用这些谓词函数筛选混合实例数组时,TypeScript能正确推导结果类型:
class A { } class B { } const isA = (x: any): x is A => { return x instanceof A; }; const isB = (x: any): x is B => { return x instanceof B; }; const arr: Array<A | B> = [new A(), new A(), new B()] const onlyA = arr.filter(isA) // 类型:A[] const onlyB = arr.filter(isB) // 类型:B[]
需求目标
实现getInstance()函数:
- 接收包含
"a"和/或"b"的字符串数组 - 返回对应名称的类实例数组,类型推导需符合预期:
getInstance(["a"])返回类型为A[](与onlyA一致)getInstance(["a","b"])返回类型为(A | B)[]
现有实现的问题
尝试通过对象关联字符串与谓词函数,泛型约束为对象键,但类型推导失效,且存在逻辑错误:
const Obj = { a: isA, b: isB } const getInstance = <T extends keyof typeof Obj>(types: T[]) => { const fns = types.map(type => Obj[type]) const set = fns.map(fn => arr.filter(() => fn)) // 逻辑错误:未正确使用谓词函数作为筛选条件 return set.flat(1) } const retA = getInstance(["a"]) // 错误推导为(A | B)[],预期为A[] const retAB = getInstance(["a", "b"]) // 预期为(A | B)[]
解决方案
步骤1:优化对象类型推断
给关联对象加上as const,让TypeScript保留更精确的键值类型关联;
步骤2:定义键到实例类型的映射
通过条件类型提取谓词函数对应的实例类型;
步骤3:修正筛选逻辑并指定返回类型
直接使用谓词函数作为filter的回调,同时明确函数返回类型,让TypeScript正确推导结果。
完整代码:
class A { } class B { } const isA = (x: any): x is A => { return x instanceof A; }; const isB = (x: any): x is B => { return x instanceof B; }; const arr: Array<A | B> = [new A(), new A(), new B()] // 加上as const让TypeScript推断精确的键值类型关联 const Obj = { a: isA, b: isB } as const; // 定义键到对应实例类型的映射类型 type KeyToInstance<K extends keyof typeof Obj> = typeof Obj[K] extends (x: any) => x is infer T ? T : never; const getInstance = <T extends keyof typeof Obj>(types: T[]): KeyToInstance<T>[] => { const result: KeyToInstance<T>[] = []; for (const type of types) { // 直接使用谓词函数作为筛选条件 result.push(...arr.filter(Obj[type])); } return result; }; const retA = getInstance(["a"]) // 类型:A[](符合预期) const retAB = getInstance(["a", "b"]) // 类型:(A | B)[](符合预期)
关键说明
as const确保Obj的键值类型不会被宽泛推断,TypeScript能准确关联"a"对应isA、"b"对应isB;KeyToInstance类型通过条件类型提取谓词函数的类型断言结果(即目标实例类型);- 循环筛选并合并结果的方式,既修正了原代码的逻辑错误,也让TypeScript能清晰推导返回数组的元素类型。
内容的提问来源于stack exchange,提问作者Islander44
相关产品推荐
相关产品推荐

