TypeScript中类型字面量与类型参数表现差异原因及适配方案
问题解析与解决方案
为什么两种写法表现不同?
核心原因是TypeScript条件类型的「分配性」行为:
- 当条件类型中
extends的左侧是裸类型参数(比如你定义的V)时,TypeScript会对联合类型进行「分配式判断」——把联合拆成单个成员分别执行条件判断,再将结果合并成新的联合。 - 而直接写
null | undefined extends O[K]时,左侧是具体的联合字面量,不是裸类型参数,不会触发分配性,只会整体判断null | undefined这个联合是否能赋值给O[K]。
具体到你的例子:
- 第一种写法(直接用
null | undefined):
对TestRange的undefined属性,判断null | undefined extends undefined?显然不成立(null无法赋值给undefined),所以这个键被排除,最终结果只有"nullish"。 - 第二种写法(用类型参数
V):V是null | undefined这个裸联合参数,条件V extends O[K]会被拆成两个独立判断:null extends undefined ? K : never和undefined extends undefined ? K : never。后者判断成立,所以"undefined"被保留,最终结果是"undefined" | "nullish"。
如何让NullishKeysIn适配联合类型参数?
要避免分配性判断,只需把裸类型参数V包裹起来(比如用元组),让extends左侧不再是裸参数,就能整体判断联合类型是否能赋值给O[K]。修改后的类型如下:
type NullishKeysIn<O, V = null | undefined> = { [K in keyof O]: [V] extends [O[K]] ? K : never }[keyof O]
测试验证:
interface TestRange { undefined: undefined, nullish: null | undefined, } // 正确触发错误:'"undefined"' 不能赋值给 '"nullish"' let prop1: NullishKeysIn<TestRange> = 'undefined' as const // 正常通过 let prop2: NullishKeysIn<TestRange> = 'nullish' as const // 自定义联合类型参数的情况也能正常工作 type CustomNullish = null | undefined | void type CustomKeys = NullishKeysIn<{ a: void, b: null | void, c: string }, CustomNullish> // CustomKeys 的类型是 "a" | "b"
这样修改后,无论是使用默认的null | undefined,还是传入自定义的联合类型参数,NullishKeysIn都会按照「整体判断联合是否能赋值给属性类型」的逻辑工作,符合预期。
内容的提问来源于stack exchange,提问作者bleistift2
相关产品推荐
相关产品推荐

