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

TypeScript类型不兼容(TS2345)及Filter类型推导问题求解

问题解决方法

1. 修复Filter类型推导问题

原定义中TableHeader使用Record<string, FieldHeader<I>>,导致每个字段类型都是FieldHeader<I>联合类型,TypeScript无法跟踪每个字段的具体类型信息。我们需要拆分类型定义,保留单个字段的类型细节:

interface TypeMap {
  boolean: boolean;
  number: number;
  string: string;
}

interface Item {
  id: string;
}

// 单个类型对应的FieldHeader,用于保留具体类型信息
type SingleFieldHeader<I extends Item, Type extends keyof TypeMap> = {
  compare: (a: TypeMap[Type], b: TypeMap[Type]) => number;
  filter: (value: TypeMap[Type], input: TypeMap[Type]) => boolean;
  get: (item: I) => TypeMap[Type] | null | undefined;
  type: Type;
};

// 原联合类型保留,兼容原有场景
type FieldHeader<I extends Item> = SingleFieldHeader<I, keyof TypeMap>;

// 修改TableHeader定义,不再强制为Record,而是允许任意包含FieldHeader的对象
type TableHeader<I extends Item> = {
  [key: string]: FieldHeader<I>;
};

// 用条件类型提取每个字段的具体类型,生成正确的Filter
type Filter<I extends Item, T extends TableHeader<I>> = {
  [Field in keyof T]: T[Field] extends SingleFieldHeader<I, infer Type> 
    ? TypeMap[Type] 
    : never;
};

修改后Filter会正确推导每个字段的类型:比如如果TableHeader中有一个name字段是SingleFieldHeader<MyItem, 'string'>,那么Filter中name的类型就是string,且无法给Filter设置任意键值对。

2. 修复applyFilter函数的类型错误

原函数中Object.entries返回的键是string类型,导致TypeScript无法关联tableHeader[key]和filter[key]的类型匹配。我们可以通过两种方式解决:

方案1:泛型辅助函数+类型断言

function applyFilter<I extends Item, T extends TableHeader<I>>(item: I, tableHeader: T, filter: Filter<I, T>) {
  // 泛型函数处理单个字段,确保键对应的类型一致
  function handleField<Key extends keyof T>(key: Key) {
    const header = tableHeader[key];
    const input = filter[key];
    const value = header.get(item);

    if (value != null) {
      // 断言header为具体的SingleFieldHeader,让TypeScript确认参数类型匹配
      (header as SingleFieldHeader<I, keyof TypeMap>).filter(value, input);
    }
  }

  // 将Object.keys结果断言为keyof T数组,确保类型安全
  (Object.keys(tableHeader) as Array<keyof T>).forEach(handleField);
}

方案2:通过switch缩小类型范围(更严谨)

如果不想用类型断言,可以通过type字段的字面量类型进行类型缩小:

function applyFilter<I extends Item, T extends TableHeader<I>>(item: I, tableHeader: T, filter: Filter<I, T>) {
  (Object.keys(tableHeader) as Array<keyof T>).forEach((key) => {
    const header = tableHeader[key];
    const input = filter[key];
    const value = header.get(item);

    if (value != null) {
      switch (header.type) {
        case 'boolean':
          header.filter(value as boolean, input as boolean);
          break;
        case 'number':
          header.filter(value as number, input as number);
          break;
        case 'string':
          header.filter(value as string, input as string);
          break;
      }
    }
  });
}

两种方案都能解决Argument of type 'string | number | boolean' is not assignable to parameter of type 'never'的错误。

内容的提问来源于stack exchange,提问作者striderhobbit

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.20 09:02:52