typescript内置Exclude怎么去理解?

/**
 * Exclude from T those types that are assignable to U
 */
type Exclude<T, U> = T extends U ? never : T;

/**
 * Extract from T those types that are assignable to U
 */
type Extract<T, U> = T extends U ? T : never;

做个测试
image.png
因为a是a b c 的子集所以P是never,这个好理解

image.png
O居然返回的是10,按照语义,T extends U ? never : TT不是U的子集,那么返回的就应该是T,也就是a 10 ,但是推断出来的是a,这个怎么解释?

阅读 6.8k
2 个回答

这跟 typescript 2.8引入的有条件类型里的所谓裸类型有关,细节你可以看这个 conditional-types,这个是个简单的描述 Typescript: what is a “naked type parameter”

// 你以为的 Exclude
type c = 'a' | 10 extends 'a' | 'b' | 'c' ? never : 'a' | 10
// 实际上的 Exclude
type c =
  | ('a' extends 'a' | 'b' | 'c' ? never : 'a')
  | (10 extends 'a' | 'b' | 'c' ? never : 10)
新手上路,请多包涵

条件类型作用于泛型内,且入参为联合类型(a|b)时,它们就会变成分布式的:

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

type Str = 'a' | 'b' | 'c';

type R = Exclude<'a' | 'd', Str>;

// 相当于
type R = Exclude<'a', Str> | Exclude<'d', Str>
// 也相当于
type R = never | 'd'

// 所以
type R = 'd'

另外提一点,如果想避免这种行为,可以这样写;

type Exclude<T, U> = [T] extends [U] ? never : T;

type Str = 'a' | 'b' | 'c';
type R = Exclude<'a' | 'd', Str>;
type R = never
撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进