TypeScript中Field数组赋值出现ts(2322)类型不兼容错误求助
首先看完整的代码示例:
interface Item { id: string; } interface BaseFieldHeader< item extends Item, value extends boolean | number | string > { get: (item: item) => value; } type FieldHeader<item extends Item> = | (BaseFieldHeader<item, boolean> & { type: 'boolean'; }) | (BaseFieldHeader<item, number> & { type: 'number'; }) | (BaseFieldHeader<item, string> & { type: 'string'; }); interface BaseField<value extends boolean | number | string> { key: string; value: value; } type Field = | (BaseField<boolean> & { type: 'boolean'; }) | (BaseField<number> & { type: 'number'; }) | (BaseField<string> & { type: 'string'; }); type TableHeader<item extends Item> = Record< string, FieldHeader<item> >; interface User extends Item { age: number; } const tableHeader: TableHeader<User> = { age: { get: (user) => user.age, type: "number" } } const user: User = { id: "frank", age: 34 } const tableRow: Field[] = Object.entries(tableHeader).map( ([key, field]) => ({ key, value: field.get(user), type: field.type, } ) )
运行后出现的错误信息:
Type '{ key: string; value: string | number | boolean; type: "string" | "number" | "boolean"; }[]' is not assignable to type 'Field[]'.
Type '{ key: string; value: string | number | boolean; type: "string" | "number" | "boolean"; }' is not assignable to type 'Field'.
Type '{ key: string; value: string | number | boolean; type: "string" | "number" | "boolean"; }' is not assignable to type 'BaseField& { type: "string"; }'.
Type '{ key: string; value: string | number | boolean; type: "string" | "number" | "boolean"; }' is not assignable to type 'BaseField'.
Types of property 'value' are incompatible.
Type 'string | number | boolean' is not assignable to type 'string'.
Type 'number' is not assignable to type 'string'.(2322)
错误原因
- 类型追踪失效:
TableHeader<User>本质是Record<string, FieldHeader<User>>,TypeScript无法记住tableHeader里每个字段对应的具体FieldHeader子类型(比如这里age对应的是number类型的FieldHeader),只能把每个field当成FieldHeader<User>的联合类型处理。 - 类型被宽泛化:遍历
Object.entries(tableHeader)时,TypeScript会把field.type推断成"string"|"number"|"boolean"的联合类型,field.get(user)的返回值也变成string|number|boolean,最终生成的对象类型是{ key: string; value: string|number|boolean; type: "string"|"number"|"boolean" }。 - 联合类型不匹配:
Field是严格互斥的联合类型,要求type和value必须一一对应(比如type: "number"必须搭配value: number),但当前生成的对象里type和value是各自独立的联合关系,TypeScript无法保证两者的对应性,因此判定该对象不能赋值给Field类型。
内容的提问来源于stack exchange,提问作者striderhobbit

