面试题答案
一键面试type MyExclude<T, U> = T extends U? never : T;
类型推断在条件类型判断中的作用和表现
在 MyExclude
的实现中,T extends U? never : T
这一条件类型判断语句利用了类型推断。这里 T extends U
尝试判断类型 T
的每一个子类型是否可以赋值给类型 U
。如果可以,就返回 never
类型,表示这个子类型需要被排除;如果不可以,就返回 T
本身。例如,对于 MyExclude< 'a' | 'b' | 'c', 'a' | 'c' >
,'a'
和 'c'
可以赋值给 'a' | 'c'
,所以会被推断为 never
,而 'b'
不能赋值给 'a' | 'c'
,就会保持不变。这就是类型推断在条件类型判断中的体现,它能够根据类型之间的赋值兼容性来决定返回的类型。
分布式条件类型
在上述实现中,当 T
是联合类型时,条件类型会自动分布式处理。比如 MyExclude< 'a' | 'b' | 'c', 'a' | 'c' >
,实际上会被处理为 ('a' extends 'a' | 'c'? never : 'a') | ('b' extends 'a' | 'c'? never : 'b') | ('c' extends 'a' | 'c'? never : 'c')
,然后根据条件类型判断结果,最终得到 'b'
。分布式条件类型使得我们在处理联合类型时无需手动遍历联合类型的每一个成员,大大简化了代码。
类型递归中的作用和表现
虽然在 MyExclude
的基本实现中没有用到类型递归,但在一些复杂场景下,类型递归会很有用。例如,如果需要处理嵌套类型结构。假设我们有一个嵌套的联合类型,需要递归地排除某些类型。在递归过程中,类型推断起着决定何时终止递归以及如何处理递归层级中的类型关系的作用。例如,在递归函数类型定义中,每次递归调用时,类型推断会确定传入参数的类型是否符合要求,以及返回类型如何与整体类型系统兼容。
处理类型循环问题
在类型递归中很容易出现类型循环问题,比如定义 type Loop<T = T> = T
,这会导致无限循环。为了避免这种情况,在使用类型递归时,要确保递归有终止条件。一种常见的方式是在递归过程中不断缩小类型范围。例如,如果我们要递归处理一个树形结构类型,每次递归可以处理树的一层节点,通过减少层级信息来确保最终递归会结束。在条件类型中,可以通过判断是否达到某个基础类型或者是否已经处理完所有层级来作为终止条件,防止出现类型循环。