You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

TypeScript中带类型守卫的通用filter+map工具函数实现问题

问题分析与解决方案

你的错误核心是泛型约束方向搞反了,同时过滤函数的类型定义不符合TypeScript的类型谓词逻辑,导致类型推断失败。

错误原因拆解

  1. 泛型约束逻辑倒置:
    你的items数组元素类型是A(此处为number | undefined),B是过滤后保留的目标类型(此处为number),正确逻辑应为**B是A的子集**,也就是B extends A。而原代码中A extends B要求原数组元素必须是B的子类,这和你传入的number | undefined无法匹配number的情况直接冲突,因此触发类型错误。
  2. 过滤函数类型定义不合理:
    你传入的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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.14 01:13:19