乐趣区

关于typescript:typescript-type-分配条件类型

接上文 type challenge(easy 局部)
对于调配条件类型,官网文档形容地址。

之前看的时候没真正了解,对于联结类型的调配条件,官网文档其实也没有讲得很明确,和翻译无关,英文文档一样很含糊,这些天做type challenge,发现有些题做进去的后果和预期不太统一,所以从新梳理这块内容。

先说论断

联结类型什么时候会调配,必须合乎 4 个条件(前面间接用条件 1、条件 2 等代指上面条件):

  1. 首先,只调配 extends 前的内容

    • 无论这个 extends 是不是子断言语句中的
    • 例如 type Test<T> = 'b' extends 'b' ? (T extends 'b' ? true: false) : false;, 其中的T extends 'b' 在子语句中,但事实上仍旧是无效的
  2. 调配的内容未做任何解决

    • type Test<T> = keyof T extends null ? never: false;Tkeyof 操作符解决了,因而不会调配
    • 官网文档中,提到防止调配的办法type ToArrayNonDist<Type> = [Type] extends [any] ? Type[] : never;,能躲避调配也是这个情理
  3. 调配内容必须作为参数传入
  4. 传入时是联结类型

相干题目与解析

验证条件 1

type Test<T> = 'b' extends 'b' ? (T extends 'b' ? true: false) : false;
Test<'a'| 'b'> // boolean

可见在子条件中的 extends 也合乎主动调配,否则 'a'|'b' extends 'b' 会返回false,而不是true|false

验证条件 2

发现这个问题是在 DeepReadonly,题目地址

这一题一看看过来,间接写出如下:

type DeepReadonly<T> = keyof T extends never ? T : {readonly [k in keyof T]: DeepReadonly<T[k]>};

然而发现对于测试用例 X2 不失效

type X2 = {a: string} | {b: number};
DeepReadonly<X2> // {a: string} | {b: number}

认真看,尽管 X2 是联结类型,但 keyof T extends never 显然不合乎后面说的 条件 2 ,因而不会主动调配,而 keyof ({a: string} | {b: number}) 值为never。因而该题正确写法如下:

type DeepReadonly<T> = {readonly [P in keyof T]: keyof T[P] extends never ? T[P] : DeepReadonly<T[P]>;
};

验证条件 3

显然,一般应用 extands 不会触发主动调配

type Test = 'a'|'b' extends 'a' ? true: false; // false

那么,假如传入的参数是联结类型,extends前的对象也是联结类型呢?

type Test<T> = 'b' extends 'b' ? (keyof T extends 'b' ? true: false) : false;
type Result = Test<{a:1,b:string}|{a:2,b:number}> // false

这里,参数 T 是联结类型,但 extends 前进行了 keyof 解决,但 keyof {a:1,b:string}|{a:2,b:number} 后果为 'a'|'b',仍然是联结类型,若这里进行了主动调配,后果应是boolean 而非false

依据后果来看,这里并未进行调配,这个例子同时违反了 条件 2 条件 3

验证条件 4

type Test<T> = 'a'|'b' extends 'b' ? T: false;
Test<5> // false

条件 4 不言而喻,官网文档上曾经说的很明确了。

不留神优先级导致的谬误

在测试调配条件类型的法则时,曾因为一条用例卡了半天,用例如下:

type A = keyof null|undefined; // undefined
type UndefinedExtendsNull = undefined extends null ? true: false; //false
type Test<T> = keyof T extends null ? true: false;
Test<null|undefined>; // true!!!!

此时曾经晓得了,keyof T会防止主动调配,因而对于Test<null|undefined>,能够写成

keyof null|undefined extends null ? true : false; // 这里有个坑...

keyof null|undefined 后果是undefined,然而

type UndefinedExtendsNull = undefined extends null ? true: false; //false

后果是false,同样的式子,后果不一样,一开始我认为是调配法则的了解有问题,但即便调配了,后果也应该是true|false,也就是boolean,而不是true

起初发现,type是有 优先级 的,且 keyof 优先级高于|.

按理说 keyof null|undefined 后果应该是never,之所以会显示后果是undefined,是因为优先级运算:

keyof null|undefined -> (keyof null)|undefined -> never|undefined -> undefined

在理论写类型的时候,要重点留神优先级问题

退出移动版