代码
type ServiceSingleKeys<T> = [T] extends (
T extends 'foo' | 'oof' ? [T] : never
) ? T : never;
具有判断整个输入类型T
是否可分配给union type "foo" | "oof"
的效果.如果是,则返回T
.如果不是,则返回never
.所以你会得到这样的行为:
type A = ServiceSingleKeys<"foo" | "oof"> // "foo" | "oof"
type B = ServiceSingleKeys<"foo"> // "foo"
type C = ServiceSingleKeys<"foo" | "bar"> // never
类型A
和B
与它们的输入相同,因为"foo" | "oof"
和"foo"
都可以赋给"foo" | "oof"
.类型C
是never
,因为"foo" | "bar"
是not可赋值给"foo" | "oof"
.
这可以更简单地重写为:
type ServiceSingleKeys<T> = [T] extends ['foo' | 'oof'] ? T : never;
type A = ServiceSingleKeys<"foo" | "oof"> // "foo" | "oof"
type B = ServiceSingleKeys<"foo"> // "foo"
type C = ServiceSingleKeys<"foo" | "bar"> // never
事实上,如果我需要的话,这就是我写这样一个类型的方式.我说不出为什么原版是这样写的.我的guess%是通过试验和错误组装而成的.(如果事实证明这两个版本在功能上不等价,那么maybe那个边缘情况就是原因,但没有更多的信息,我对此持怀疑态度).
在不更改行为的情况下,您无法从支票中移除tuple type包装器:
type NotServiceSingleKeys<T> = T extends 'foo' | 'oof' ? T : never;
type A = NotServiceSingleKeys<"foo" | "oof"> // "foo" | "oof"
type B = NotServiceSingleKeys<"foo"> // "foo"
type C = NotServiceSingleKeys<"foo" | "bar"> // "foo" <-- difference
这是因为选中的类型是纯泛型类型参数的条件类型是distributive conditional type,其中输入类型在求值之前被分解为其单个联合成员,而输出被联接到新的联合中.所以NotServiceSingleKeys<"foo" | "bar">
的计算结果是NotServiceSingleKeys<"foo"> | NotServiceSingleKeys<"bar">
,它变成了"foo" | never
,或者仅仅是"foo"
.
分布式条件类型通常是人们想要看到的(这允许您获得像the Extract<T, U>
utility type这样的联合过滤行为),但是当它不受欢迎时,修复方法通常是将extends
判断的两个方面都包装在一个元组中.判断[T] extends ['foo' | 'oof']
是非分配的,因为[T]
不是纯泛型类型参数,但是判断是相似的,因为元组是协变的(这意味着当且仅当XXX
可分配给YYY
时,[XXX]
才是可分配给[YYY]
的).正如上面链接的documentation中所说的:
通常,分布性是所需的行为.为了避免这种行为,您可以用方括号将extends
关键字的两边括起来.
同样,我在这里的guess点是,代码的原始版本是一种反复try 的try ,目的是应用该建议,以防止判断意外分发.如果问题中的特定嵌套条件类型还有其他目的,我看不出来.
Playground link to code个