ReturnType 辅助类型中的 TypeScript 类型推断
我无法理解为什么在下面的情况中 Temp 类型是 never。我理解为什么它与 (...args: any) => infer R 兼容,但它是如何被推断为 never 类型的呢?
// type ReturnType<T extends (...args: any) => any> = T extends (...args: any) => infer R ? R : any;
type Temp = ReturnType<never>;
答案#1
TL;DR 分配条件类型和 never 是空联合
长版本:
让我们首先理解为什么 ReturnType<never> 为 never 一开始会有点令人惊讶:
来自介绍 never 类型的 PR:
never 是每种类型的子类型并且可以赋值给每种类型。
所以这意味着如果我们问这个问题:never 扩展 AnyOtherType?答案应该永远是是的。那么让我们把这个问题问编译器:
type R = never extends (...args: any) => any ? "Y" : "N"; // Evaluates to "Y"
游乐场链接
所以这个定义确实成立,并且 never 是 (...args: any) => any 的子类型。但为什么 ReturnType<never> 会解析为 never 呢?如果推断失败,默认值通常是 unknown 而不是 never(参考)。让我们在 ReturnType 之外尝试这个推断:
type T0 = never extends (...args: any) => infer R ? R : any; //unknown
游乐场链接
所以这里我们有一个非常令人惊讶的结果,T0 确实是 unknown,而 ReturnType<never> 是 never,尽管我们所做的只是将 ReturnType 的定义内联到 T0 中。
其原因是分配条件类型。对裸类型参数有条件的类型是分配类型。这意味着如果 T 是一个联合类型,每个联合成员都会独立地通过条件类型处理,所有独立的结果将被联合以得到最终结果。例如:
type T1 = ReturnType<(()=> number) | (() => string)> // number | string
编译器如何评估上面的类型:
ReturnType<(()=> number) | (() => string)>
-> ReturnType<()=> number> | ReturnType<() => string>
-> ((()=> number) extends (...args: any) => infer R) | ((()=> string) extends (...args: any) => infer R)
-> number | string
好的,那么这与 never 有什么关系呢。实际上,never 是空联合类型(参考),一个没有任何成员的联合类型。这意味着当将 never 传入分布式条件类型时,条件类型实际上不会被求值,因为在尝试分发时,没有任何可分发的内容。
我们可以通过不让 T 直接使用,而是将其放在元组中,例如,来创建一个非分配版本的 ReturnType:
type ReturnTypeNonDistributive<T extends (...args: any) => any> = [T] extends [(...args: any) => infer R] ? R : any;
type Temp2 = ReturnTypeNonDistributive<never>; //unknown
游乐场链接
