TypeScript定义互斥对象属性时可选属性应使用void还是never
互斥对象属性类型标注选择:
void 还是 never 核心结论
这个场景下应该使用never,void属于语义误用。
原因说明
1. 两者语义完全不同
void的设计语义是标记函数无返回值,代表“值存在但不应被消费”,本身就合法接受undefined赋值,和你要表达的「这个属性根本不允许存在」的需求完全不匹配。never的设计语义是“不存在任何符合该类型的值”,刚好匹配互斥场景下「禁止该属性出现有效值」的需求。
2. 为什么测试时x?: never能接受undefined
这不是never类型本身的问题,是TypeScript可选属性的默认行为导致的:
在默认配置下,只要属性加了
?可选标记,TypeScript会自动给属性类型追加| undefined,也就是说a?: never等价于a?: never | undefined,自然可以接受undefined赋值。
实现严格互斥的正确写法
要彻底禁止互斥属性显式传undefined、同时禁止两个属性同时存在,只需要两步:
- 在tsconfig中开启
exactOptionalPropertyTypes配置,开启后可选属性不会自动追加| undefined类型
{ "compilerOptions": { "exactOptionalPropertyTypes": true } }
- 用
never标记互斥侧的可选属性
type T1 = { a?: never, b: string, } type T2 = { a: string, b?: never, } type TAllowed = T1 | T2 // 以下写法均合法 const t1: TAllowed = { a: 'abc' } const t2: TAllowed = { b: 'bcd' } // 以下写法均会抛出类型错误,达到严格互斥效果 const t3: TAllowed = { a: 'abc', b: 'cde' } // 同时存在a、b属性报错 const t4: TAllowed = { a: 'abc', b: undefined } // 互斥属性显式传undefined报错 const t5: TAllowed = { b: 'bcd', a: undefined } // 互斥属性显式传undefined报错
为什么不推荐用void
如果用a?: void标记互斥属性,哪怕开启了exactOptionalPropertyTypes,你依然可以合法给a赋值undefined——因为undefined本身就是void类型的合法值,无法达到“属性完全不允许出现”的严格互斥要求,语义上也不符合类型设计的初衷。
内容的提问来源于stack exchange,提问作者Moon
相关产品推荐
相关产品推荐

