如何构造要么含某类型全属性要么无属性的TypeScript类型?
解决方案:构造“全有或全无”的TypeScript类型
要实现要么拥有给定类型的全部属性、要么完全没有属性的类型,你可以定义一个泛型类型,让它要么是原类型本身,要么是一个包含原类型所有属性但这些属性可选且类型为never的对象——这样能让TypeScript精准区分两种情况,当检测到任意一个属性存在时,自动推断出所有属性都存在。
具体实现代码
interface I { x: number; y: number; } // 定义泛型类型:要么是完整的T,要么T的所有属性可选且类型为never type FullOrNothing<T> = T | { [K in keyof T]?: never }; const f = (arg: FullOrNothing<I>) => { // 用严格判断排除undefined,避免空字符串、0等假值干扰 if (arg.x !== undefined) { console.log(arg.y + 1); // 此时arg.y的类型是number,无undefined } };
为什么这个方案可行
FullOrNothing<I>包含两个明确分支:- 完整的
I类型:必须包含x和y且都是number类型; - 空分支:
I的所有属性都是可选的,且属性类型为never——意味着这些属性要么不存在,要么存在但不可能有合法值(never类型没有实际取值)。
- 完整的
- 当你通过
arg.x !== undefined判断时,TypeScript会自动排除空分支(因为空分支里x要么不存在,要么值是never,不可能通过这个判断),因此此时arg会被收窄为I类型,arg.y自然就是确定的number类型。
为什么原来的方案不行
你之前用I | Record<string, undefined>的问题在于:Record<string, undefined>允许对象存在任意字符串键的属性,且值为undefined。TypeScript无法通过arg.x的存在性判断,精准排除掉arg是{x: number, y: undefined}这类不符合预期的对象,因此会保留arg.y为number | undefined的可能性。
而替换成never的方案(I | Record<string, never>)会导致TypeScript错误认为arg.x始终是number,因为Record<string, never>意味着所有属性的类型都是never,不存在合法取值,TypeScript会直接忽略这个分支,把arg的类型当成I。
内容的提问来源于stack exchange,提问作者Alexey Romanov
相关产品推荐
相关产品推荐

