否定打字稿类型?

时间:2018-08-11 03:28:28

标签: typescript negation

我想在Typescript中创建一个简单的NOT运算符,在该脚本中,您将所有原始组合成某种类型A的并集,它们不是第二种类型B的并集的原语成员。这可以使用条件类型来完成。例如,如果您有以下类型:

type A = 'a' | 'b' | 'c';
type B = 'c' | 'd' | 'e'; 

...然后我想将它们映射到第三个派生类型[A-B],在这种情况下,它会产生:

type C = 'a' | 'b'

使用以下所示形式的条件似乎可以做到这一点。但是,我完全感到困惑,为什么下面的NOT运算符似乎可以满足我的要求,但是明确拼写出完全相同的条件逻辑却没有:

type not_A_B_1 = A extends B ? never : A;   // 'a' | 'b' | 'c'

type Not<T, U> = T extends U ? never : T;   
type not_A_B_2 = Not<A, B>                  // 'a' | 'b'

请参见here

有人可以告诉我我是否在这里缺少一些TS微妙之处,这可以解释为什么not_A_B_1not_A_B_2不相等吗?谢谢。

2 个答案:

答案 0 :(得分:4)

您遇到了distributive conditional types

  

其中选中的类型为裸类型参数的条件类型称为分布式条件类型。实例化期间,分布条件类型自动在联合类型上分布。例如,将T extends U ? X : Y的类型为A | B | C的类型为T的实例化为(A extends U ? X : Y) | (B extends U ? X : Y) | (C extends U ? X : Y)

在此:

type not_A_B_1 = A extends B ? never : A;   // 'a' | 'b' | 'c'

A是具体类型,而不是类型参数,因此条件类型不会分布在其组成部分上。

但是在

type Not<T, U> = T extends U ? never : T;   

T是一个裸类型参数,因此条件类型确实得到分发。 “裸”是什么意思?这意味着TT的某些类型函数相反。因此,在{foo: T} extends W ? X : Y中,类型参数T是“衣服”,因此它不会分布。

这导致一种不需要时可以关闭分布式条件类型的方法:给type参数穿上衣服。最简单且最不冗长的方法是使用一个元素的tuple:因此,

T extends U ? V : W // naked T
[T] extends [U] ? V : W // clothed T

由于[T] extends [U]T extends U时应为真,因此除分布性外,其余均等价。因此,让我们将Not<>更改为非分布式:

type NotNoDistribute<T, U> = [T] extends [U] ? never : T;   
type not_A_B_2 = NotNoDistribute<A, B>                  // 'a' | 'b' | 'c'

现在not_A_B_2not_A_B_1相同。如果您喜欢原始的not_A_B_2行为,请使用Not<>之类的分布式条件类型。如果您喜欢非分配行为,请使用具体类型或衣服类型参数。这有道理吗?

顺便说一下,您的Not<T,U>类型在标准库中已经以predefined type的形式出现在Exclude<T,U>中,这意味着要“从T中排除那些可分配的类型到U”。

希望有帮助。祝你好运!

答案 1 :(得分:0)

Typescript 3.5支持否定类型。

https://github.com/Microsoft/TypeScript/issues/30555