TypeScript类型识别疑问:为何未检测到属性缺失错误?
问题
定义常量时指定了TT类型,但TypeScript未抛出预期错误:常量C同时包含number_:'N'和string_:'S'属性,且缺少valueN,但并未触发报错。代码示例如下:
// example type TT = string | {string_:'S', valueS:string} | {number_:'N', valueN:number}; function run(p:TT):number{ if(typeof p === 'string'){ throw ''; } if('number_' in p){ return p.valueN; } throw ''; } const C:TT = {number_:'N',string_:'S',valueS:'text'}; console.log(run(C));
原因解释
TypeScript采用结构类型系统,联合类型的检查逻辑是:只要值符合联合类型中至少一个成员的结构要求,就会被认为属于该联合类型。
你的代码里,常量C的结构{number_:'N',string_:'S',valueS:'text'}完全匹配TT中的{string_:'S', valueS:string}成员——虽然多了number_:'N'属性,但TypeScript默认允许对象存在额外属性(除非开启严格的额外属性检查或使用精确类型约束)。因此TypeScript判定C属于TT类型,不会抛出缺少valueN的错误。
当run函数处理C时,'number_' in p检查为真,函数会尝试返回p.valueN,但该属性不存在,最终会在运行时抛出错误。
改进方案
方案1:使用互斥属性的可辨识联合
修改TT类型,为每个对象成员添加互斥的可选never类型属性,确保对象只能符合联合类型中的一个成员:
type TT = string | {string_:'S', valueS:string, number_?: never} | {number_:'N', valueN:number, string_?: never}; function run(p:TT):number{ if(typeof p === 'string'){ throw ''; } if('number_' in p){ return p.valueN; } throw ''; } // 此时会报错:类型 "{ number_: 'N'; string_: 'S'; valueS: string; }" 不能分配给类型 "TT" const C:TT = {number_:'N',string_:'S',valueS:'text'};
方案2:使用satisfies操作符(TypeScript 4.9+)
satisfies操作符会先推断常量的实际类型,再检查是否符合目标类型,同时保留常量的具体类型信息,且不允许额外属性导致的类型不匹配:
type TT = string | {string_:'S', valueS:string} | {number_:'N', valueN:number}; function run(p:TT):number{ if(typeof p === 'string'){ throw ''; } if('number_' in p){ return p.valueN; } throw ''; } // 此时会报错:类型 "{ number_: 'N'; string_: 'S'; valueS: string; }" 不满足类型 "TT" const C = {number_:'N',string_:'S',valueS:'text'} satisfies TT;
内容的提问来源于stack exchange,提问作者logrox
相关产品推荐
相关产品推荐

