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
相关产品推荐
相关产品推荐

