在这个例子中:
type Action<T extends string, P = never> = {
type: T;
} & ([P] extends [never]
? {}
: {
payload: P;
});
为什么我们需要在条件周围加上方括号[P] extends [never]
,如果我们不这样使用它有什么区别P extends never
?
我明白这种类型在做什么,只是找不到解释为什么我们实际上需要方括号以及为什么没有方括号就不起作用。
编辑:让我尝试更简单的例子:
type GetTest<T = never> = [T] extends [never] ? string : number;
type Test = GetTest; // type Test = string;
这里type Test = string
正如预期的那样。但我没有得到的是,当我们没有方括号时,条件会发生什么,我们没有得到,string
但我们也没有得到 a number
,相反,我们得到了type Test = never
type GetTest<T = never> = T extends never ? string : number;
type Test = GetTest; // type Test = never
如果您有一个条件类型,其中正在检查的类型( 的左侧
extends
)是泛型类型参数,则它会成为分布式条件类型。所以在GetTestDist<T>
是分布式条件类型,因为T
是泛型类型参数,而GetTestNonDist<T>
is 不是,因为[T]
不是泛型类型参数。是的,
[T]
涉及泛型类型参数T
,但它本身不是类型参数。有时人们会说T
inT extends never ? ⋯ : ⋯
是裸类型参数或裸类型参数,而不是T
in[T] extends [never] ? ⋯ : ⋯
,比如说“穿衣服的”。因此,所检查的类型是裸类型参数的条件类型是分布式条件类型。但是,这是什么意思?
当类型函数
F<T>
是分配条件类型时,该操作将分布在 中的联合上T
,这意味着它单独作用于每个联合成员并将结果连接回联合中。因此,例如,F<A | B | C>
将评估为与 相同F<A> | F<B> | F<C>
。此外,该
never
类型被认为是空联合,因此无论如何F<never>
都将始终如此。never
(有关权威来源,请参阅microsoft/TypeScript#23182 上的相关评论)。这种处理
never
可能会令人困惑,但它是一致的。该never
类型被吸收到联合中:也就是说,X | never
被简化为X
无论X
是什么。x
(如果你有一个type 的值X | never
,那么x
要么是 type 的X
值,要么是 type 的值,never
但是没有type 的值,所以必须是 type 的。所以所有可分配给的值都必须可分配给,并且类型检查器通过吸收来观察这一点联合。有关更多信息,请参阅为什么永远不能分配给每种类型?)您可以将其视为联合操作的单位元素。never
x
X
X | never
X
never
never
因此,如果
X | never
等于never
,则F<X>
和F<X | never>
相同。如果F<T>
是可分配的,则F<X | never>
等价于F<X> | F<never>
。这意味着对于所有人来说F<X>
都是一样的。要实现这一点,最简单的方法是 if is just 。F<X> | F<never>
X
F<never>
never
(以此类推,假设您有一个数学函数 ?(?),它对加法具有分配性,因此 ?(?) + ?(?) = ?(?+?)。加法有一个单位元素:0,因为 ?+ 0 = ?。这意味着 ?(0) 必须为 0,因为 ?(?) + ?(0) = ?(?+0) = ?(?)。0 是“空总和”,并且是“空的和
never
”联盟”。)分配行为通常是人们所希望的,但有时却并非如此。因此,关闭这种行为的方法是用一些协变类型函数“覆盖”裸类型参数和您正在检查的类型
C<T>
。(有关方差的更多信息,请参阅TypeScript 中方差、协方差、逆变和双方差之间的差异)。您需要在 的两侧都执行此操作
extends
,以便进行相同的检查( ifC<T>
是协变的T
thenC<A> extends C<B>
意味着A extends B
)。任何协变“服装”都足够了。但是,如果您正在寻找,呃,“最简洁”的服装,以便可以节省尽可能多的击键次数,那么您应该使用
[T]
. 无论好坏,TypeScript 将数组类型视为协变(请参阅为什么 TypeScript 数组是协变的?),并且单元素元组是一种数组类型。与任何其他协变类型函数相比,没有什么比使用更“正确”的了[T]
,它只是最方便的。因此,如果您想关闭条件类型中联合的分配,通常建议您将两边都用⋯包裹
extends
起来:[
]