TypeScript空值合并运算符结果类型的疑问
TypeScript空值合并运算符结果类型的疑问
你提的这个问题其实涉及到TypeScript类型系统里对unknown和空值合并运算符的特殊处理,我来一步步给你拆解:
首先先确认你的代码的类型推断结果:
declare const a: unknown[]; const r = a[3] ?? 'hello'; // TypeScript 确实会推断出 const r: {}
你疑惑为什么不是NonNullable<unknown> | string,其实核心原因是:string本身就是NonNullable<unknown>的子类型,而TypeScript里NonNullable<unknown>会被简化为{},所以这两个写法本质上是等价的,TypeScript只是帮你做了冗余类型的合并。
具体来说:
- 对于
a[3],在默认TypeScript配置(未开启noUncheckedIndexedAccess)下,类型是unknown;如果开启了该配置,类型是unknown | undefined,但不管哪种情况,??运算符都会过滤掉null和undefined的情况,取左边的非空类型和右边的string做联合。 NonNullable<unknown>表示unknown排除null和undefined后的所有类型,而在TypeScript的类型系统中,这个集合可以被{}类型精准表示——因为{}是所有非null、非undefined值的超类型(包括原始类型如string、number,以及对象、函数等)。- 而
string本身就属于{}的子类型(你可以验证type IsStringSubsetOfObj = string extends {} ? true : false,结果是true),所以NonNullable<unknown> | string其实完全等价于NonNullable<unknown>,也就是{},TypeScript会自动把这种冗余的联合类型简化为更简洁的{}。
如果想要更直观地看到这个等价关系,可以写几个类型测试:
type NonNullableUnknown = NonNullable<unknown>; // 类型等价于 {} type UnionTest = NonNullableUnknown | string; // 类型等价于 {},因为 string 已经被包含在 NonNullableUnknown 中
所以TypeScript的推断结果是正确的,只是它做了类型简化,把你预期的{} | string合并成了更简洁的{}而已~
内容来源于stack exchange
相关产品推荐
相关产品推荐

