为什么在 TypeScript 中,不指定的泛型会被推断得不同,简单调用与空合并操作符有所区别?
为什么在下面的代码中 a 和 b 的类型不同?
function empty<T>() { return [] as T[] }
const defEmpty = empty()
function test1(abc: number[]|null) {
const a = abc ?? defEmpty
const b = abc ?? empty()
}
在 playground 中,我可以看到 a: unknown[] 和 b: number[]。我原本期望它们两个都是 unknown[] 类型。
答案#1
你在此处的 empty() 调用中没有提供显式的通用类型:
const b = abc ?? empty()
但是 Typescript 可以从表达式中推断出该类型——它知道 abc 的类型是 number[] | null,所以它会将 empty 调用的类型参数推断为 number(你可以通过你链接的 playground 里的方式看到,如果你将鼠标悬停在 empty() 上)。所以你的那一行基本上变为:
const b = abc ?? empty<number>();
因此,b 的类型也是 number[]。注意,省略泛型类型参数并不意味着它会变成 unknown。
至于类型推断究竟是如何工作的——据我所知,没有严格的规范。最后的规范版本已被存档,不再维护。与该存档规范相比,类型推断规则也发生了一些变化。因此,你能获得的最佳信息来源是文档,但文档相当模糊。相关部分称为“上下文类型”,它大致描述了 TypeScript 在许多情况下能够从上下文中推断泛型类型参数,但没有以严格的方式描述其工作原理。
然而,这个案例看起来相当清楚。在??表达式的左侧,你有已知类型的表达式,所以在右侧使用相同类型的省略泛型类型参数是合理的。
