TypeScript中带类型守卫的通用filter+map工具函数实现问题
问题分析与解决方案
你的错误核心是泛型约束方向搞反了,同时过滤函数的类型定义不符合TypeScript的类型谓词逻辑,导致类型推断失败。
错误原因拆解
- 泛型约束逻辑倒置:
你的items数组元素类型是A(此处为number | undefined),B是过滤后保留的目标类型(此处为number),正确逻辑应为**B是A的子集**,也就是B extends A。而原代码中A extends B要求原数组元素必须是B的子类,这和你传入的number | undefined无法匹配number的情况直接冲突,因此触发类型错误。 - 过滤函数类型定义不合理:
你传入的isDefined本质是带类型谓词的判断函数,但原代码中filter参数仅定义为普通布尔返回函数,既没有利用类型谓词让TS识别过滤后的类型,还错误扩大了参数范围(原数组元素只有A类型,不需要A|B)。
修正后的代码
function filterMap<A, B extends A, C>( items: A[], filter: (item: A) => item is B, mapper: (item: B) => C ): C[] { const result: C[] = []; for (const item of items) { if (filter(item)) { // 此处item会被TS自动推断为B类型,无需手动断言 result.push(mapper(item)); } } return result; } const items = [1, 2, undefined, 4, undefined, undefined, 7]; // 给判断函数添加类型谓词,明确返回true时的类型 const isDefined = (n: number | undefined): n is number => n !== undefined; const double = (n: number) => n * 2; // 现在类型完全匹配,无报错 const result = filterMap(items, isDefined, double); // result类型为number[],值为[2, 4, 8, 14]
泛型特性保留说明
修正后的函数依然保持完整的泛型灵活性:
- 支持任意类型的数组场景:比如对象数组过滤
type User = { name: string; age?: number }; const users: User[] = [{name: "Alice", age: 25}, {name: "Bob"}, {name: "Charlie", age: 30}]; const hasAge = (user: User): user is User & {age: number} => typeof user.age === "number"; const getName = (user: User & {age: number}) => user.name; filterMap(users, hasAge, getName); // 返回类型string[],值为["Alice", "Charlie"] - 自动推导泛型参数:调用时无需手动指定
A/B/C,TS会根据传入的参数自动完成类型推断。
内容的提问来源于stack exchange,提问作者amdilley
相关产品推荐
相关产品推荐

