TypeScript细碎知识点:关于type Exclude<T, U extends T> = T extends U ? never : T;
题目:实现内置的Exclude <T,U>,从 T 中排除可分配给 U 的那些类型
type x = string | number | boolean type y = string | number type c = MyExclude<x, y> const b: c = true
解答:
type MyExclude<T, U> = T extends U ? never : T
疑问:为什么 联合类型T extends U 后 “ T extends U ? never : T ” T 不再是原来的类型,而是替换掉U的类型。
这个反直觉结果的原因就是所谓的分配条件类型(Distributive Conditional Types)
分配条件类型:对于使用extends关键字的条件类型(即上面的三元表达式类型),如果extends前面的参数是一个泛型类型,当传入该参数的是联合类型,则使用分配律计算最终的结果。分配律是指,将联合类型的联合项拆成单项,分别代入条件类型,然后将每个单项代入得到的结果再联合起来,得到最终的判断结果。
举例子说明
type P<T> = T extends 'x' ? string : number; type A3 = P<'x' | 'y'> // A3的类型是 string | number
该例中,extends的前参为T,T是一个泛型参数。在A3的定义中,给T传入的是'x'和'y'的联合类型'x' | 'y',满足分配律,于是'x'和'y'被拆开,分别代入P<T>
P<'x' | 'y'> => P<'x'> | P<'y'>
'x'代入得到
'x' extends 'x' ? string : number => string
'y'代入得到
'y' extends 'x' ? string : number => number
然后将每一项代入得到的结果联合起来,得到string | number。
所以题目中 type MyExclude<T, U extends T> = T extends U ? never : T; 也满足了分配率。大概如下
type c = MyExclude<x, y> /* (string extends string | number ? never : string) | //结果: never (number extends string | number ? never : number) | //结果: never (boolean extends string | number ? never : boolean) //结果: boolean */
总之,满足两个要点即可适用分配律:第一,参数是泛型类型,第二,代入参数的是联合类型
浙公网安备 33010602011771号