为何TypeScript隐式转换{...T,[keyof T]:T[keyof T]}为T时不报错?
TypeScript泛型函数类型兼容问题解答
function mergeCell<T>( row: T, cellKey: keyof T, newValue: T[keyof T] ): T { return { ...row, [cellKey]: newValue }; } interface MyObj { a: string; b: boolean; c: number; } const obj = { a: '1', b: false, c: 2 }; const result : MyObj = mergeCell(obj, 'c', 'c'); console.log(result); // 运行结果(无报错): // { // "a": "1", // "b": false, // "c": "c" // }
问题1:为何函数返回{...row, [cellKey]: newValue}时,TypeScript不报错?
这是TypeScript结构类型系统和泛型处理逻辑共同作用的结果:
- 首先,
T[keyof T]是T所有属性值类型的联合类型,比如MyObj对应的T[keyof T]就是string | boolean | number。只要传入的newValue属于这个联合类型,参数阶段就不会触发类型错误。 - 其次,返回的对象结构完全匹配
T的属性集合,TypeScript的结构类型检查只要求对象具备目标类型的所有属性,不会强制校验属性值的精确类型——即便被修改的属性值类型是联合类型中的其他成员,只要结构符合就允许隐式转换为T。 - 另外,泛型场景下TypeScript会优先信任开发者标注的返回类型,只要返回值结构和
T兼容,就不会进行更严格的精确类型校验。
问题2:{[x: keyof T]: T[keyof T]}是否属于T的子集?
不属于。
T的每个属性都有精确的单一类型,比如MyObj中c的类型固定为number;而{[x: keyof T]: T[keyof T]}是索引类型,它的所有属性类型都是T所有属性值的联合类型,比如MyObj对应的该类型是{a: string | boolean | number; b: string | boolean | number; c: string | boolean | number}。- 子集的核心是“类型A的所有可能值都属于类型B”,但这个索引类型可以包含大量
T不允许的值(比如给a属性赋值boolean类型),因此它不是T的子集,反而T是它的子集——因为T的所有值都符合该索引类型的要求。
内容的提问来源于stack exchange,提问作者Pak Wong
相关产品推荐
相关产品推荐

