Exclude<Type, ExcludeUnion>
通过排除联合类型中的指定成员来构造新类型。
type Letter = 'a' | 'b' | 'c';
type T0 = Exclude<Letter, 'a'>;
上例代码中的类型 T0
等价于下面的写法:
type T0 = 'b' | 'c';
在这个例子中,Exclude
将联合类型 Letter
中的成员 a
排除掉,得到了一个叫 T0
的联合类型。最终在联合类型 T0
中,只有成员 b
和 成员 c
。
那么,Exclude<Type, ExcludeUnion>
是如何排除类型成员的呢?下面我们通过它的类型定义文件分析一下:
/**
* Exclude from T those types that are assignable to U
*/
type Exclude<T, U> = T extends U ? never : T;
T extends U ? nver : T
类似于 JavaScript 中的三目运算符,这是 TypeScript 2.8 中引入的条件类型1,意思是:如果 T
类型是 U
类型的子类型的话,返回 never
2,否则返回 T
类型。通过刚才的例子我们不难发现,Exclude
就是将前面的类型与后面的类型对比,过滤出前面联合类型中独有的成员。
Exclude
除了可以排除联合类型中的字符串成员,还可以过滤函数成员:
type MyUnion = 'a' | 'b' | (() => void);
type T2 = Exclude<MyUnion, Function>;
// `T2` 类型等价于下面的 `T3` 类型
type T3 = 'a' | 'b';
如果是两个联合类型呢?
type U1 = 'a' | 'b' | 'c';
type U2 = 'b' | '5' | 'c';
type U3 = Exclude<U1, U2>;
// `U3` 类型等价于下面的 `U4` 类型
type U4 = 'a';
U3
类型的结果可能让人疑惑,看上去 U1
类型并不是继承自 U2
类型,最后为什么将类型 U1
中的成员 b
和成员 c
过滤掉了呢?首先我们注意到 U1
和 U2
类型都是联合类型,换句话说 U1
类型有可能是 'a'
,有可能是 'b'
,也有可能是 'c'
。显然成员 'a'
没有继承自 U2
类型,而成员 'b'
和成员 'c'
分别继承自类型 U2
,所以,最终 Exclude
将 U1
类型中的成员 'b'
和成员 'c'
排除掉,只留下了成员 'a'
。