如何让TypeScript要求对象需先定义position才能定义innerSize?
TypeScript条件属性依赖类型定义异常解析
问题背景
需要定义一个TypeScript类型,要求仅当对象中存在position属性时,才能定义innerSize属性。尝试了如下联合类型定义:
type TypeA = { width?: number; height?: number; position: string; innerSize?: string; } | { width?: number; height?: number; position?: undefined; }
但在创建对象时出现不符合预期的情况:
function test() { const a: TypeA = {}; const b: TypeA = { width: 50, height: 75 }; const c: TypeA = { position: "5, 7" }; // 报错:Type '{ innerSize: string; }' 无法分配给TypeA,缺少position const d: TypeA = { innerSize: "400, 120" }; const e: TypeA = { width: 50, innerSize: "400, 120" }; // 却能编译通过! }
疑问:为何仅添加width属性就能绕过position必须存在才能使用innerSize的限制?
原因分析
问题出在联合类型的第二个分支{ width?: number; height?: number; position?: undefined; }:
- 这个分支只限制了
position可选为undefined,但没有对innerSize做任何限制。 - TypeScript的对象类型默认允许额外属性(除非开启严格额外属性检查或使用精确类型),所以
{ width: 50, innerSize: "400, 120" }会被匹配到第二个分支:没有position属性等价于position为undefined,符合分支要求,而额外的innerSize属性不会触发类型检查错误。
而const d: TypeA = { innerSize: "400, 120" }报错,是因为TypeScript在匹配联合类型时,会优先检查对象是否符合某个分支的必填属性,这个对象没有任何分支的必填属性,且第一个分支要求position必须存在,所以会报错;但当添加了width后,对象匹配到第二个分支的可选属性,此时额外属性不会被拦截。
解决方法
在第二个分支中明确禁止innerSize属性,通过innerSize?: never来限制该分支下innerSize只能为undefined或不存在:
type TypeA = { width?: number; height?: number; position: string; innerSize?: string; } | { width?: number; height?: number; position?: undefined; innerSize?: never; // 明确禁止innerSize存在 }
修改后,const e: TypeA = { width: 50, innerSize: "400, 120" }会触发预期的类型错误,确保只有存在position时才能定义innerSize。
内容的提问来源于stack exchange,提问作者Yasser Greyeb
相关产品推荐
相关产品推荐

