TypeScript:为何使用Omit等类型时number可赋值给string且无报错?
为什么这段TypeScript代码中
StringType可以赋值给NumberType却不报错? 这段代码无报错的核心原因,在于TypeScript的结构类型系统以及对可选属性的兼容性规则:
结构类型系统的判断逻辑
TypeScript不依赖类型名称判断兼容性,只看类型的结构是否匹配。只要源类型的结构能满足目标类型的最低要求,就允许赋值。可选属性的兼容性放宽
对于带?标记的可选属性,TypeScript默认认为该属性可以不存在(即值为undefined)。在你的代码中:NumberType和StringType的field都是可选属性,因此当field为undefined时,两者完全兼容。- 当
field存在时,内部的numberOrString也是可选属性。TypeScript认为源类型(StringType)可以选择不提供numberOrString(值为undefined),而undefined完全符合目标类型(NumberType)中numberOrString?: number的类型要求(因为number | undefined包含undefined)。
嵌套对象的兼容性判断
虽然StringType的numberOrString是string | undefined,NumberType的是number | undefined,但由于两者都是可选属性,TypeScript不会强制检查属性存在时的类型匹配——它只关注源类型是否有能力提供兼容的属性值,而忽略了源类型可能提供不兼容值的情况。
潜在风险
这种行为会隐藏运行时错误:如果StringType变量的field.numberOrString实际是string类型,赋值给NumberType变量后,TypeScript会错误地推断该属性为number | undefined,后续若将其当作number使用会引发类型不匹配问题。
修复方案
如果需要严格的类型检查,可以采用以下两种方式:
// 方案1:将numberOrString设为必填属性 type NumberType = { field?: { id: string; numberOrString: number } }; type StringType = Omit<NumberType, "field"> & { field?: { id: string } & { numberOrString: string } }; const test = (s: StringType) => { const n: NumberType = s; // 此时会触发预期的类型错误 };
// 方案2:添加运行时类型检查+类型断言 const test = (s: StringType) => { if (s.field?.numberOrString !== undefined && typeof s.field.numberOrString !== 'number') { throw new Error('numberOrString must be a number'); } const n: NumberType = s as NumberType; };
内容的提问来源于stack exchange,提问作者Shinichi Kouki
相关产品推荐
相关产品推荐

