TypeScript的extends条件类型

2021/7/27 TypeScript

条件类型

Typescript 2.8

条件类型

TypeScript2.8引入了条件类型,它能够表示非统一的类型。有条件的类型会以一个条件表达式进行类型关系检测,从而在两种类型中选择其一:

T extends U ? X : Y
1

上面的类型意思是,若T能够赋值给U,那么类型是X,否则为Y

# 条件类型

有条件的类型T extends U ? X : Y或者解析为X,或者解析为Y,再或者延迟解析,因为它可能依赖一个或多个类型变量。是否直接解析或推迟取决于:

  1. 首先,令T'U'分别为TU的实例,并将所有类型参数替换为any,如果T'不能赋值给U',则将有条件的类型解析成Y。直观上讲,如果最宽泛的T的实例不能赋值给最宽泛的U的实例,那么我们就可以断定不存在可以赋值的实例,因此可以解析为Y
  2. 其次,针对每个在U内由推断声明引入的类型变量,依据从T推断到U来收集一组候选类型(使用与泛型函数类型推断相同的推断算法)。对于给定的推断类型变量V,如果有候选类型是从协变的位置上推断出来的,那么V的类型是那些候选类型的联合。反之,如果有候选类型是从逆变的位置上推断出来的,那么V的类型是那些候选类型的交叉类型。否则V的类型是never
  3. 然后,令T''T的一个实例,所有推断的类型变量用上一步的推断结果替换,如果T''明显可赋值给U,那么将有条件的类型解析为X。除去不考虑类型变量的限制之外,明显可赋值的关系与正常的赋值关系一致。直观上,当一个类型明显可赋值给另一个类型,我们就能够知道它可以赋值给那些类型的所有实例。
  4. 否则,这个条件依赖于一个或多个类型变量,有条件的类型解析被推迟进行。
type TypeName<T> =
  T extends string ? "string" :
  T extends number ? "number" :
  T extends boolean ? "boolean" :
  T extends undefined ? "undefined" :
  T extends Function ? "function" :
  "object";

type T0 = TypeName<string>;  // "string"
type T1 = TypeName<"a">;  // "string"
type T2 = TypeName<true>;  // "boolean"
type T3 = TypeName<() => void>;  // "function"
type T4 = TypeName<string[]>;  // "object"
1
2
3
4
5
6
7
8
9
10
11
12
13

# 分布式条件类型

如果条件类型里待检查的类型是“naked type parameter”,那么它也被称为“分布式条件类型”。分布式条件类型在实例化时会自动分发成联合类型。例如,实例化T extends U ? X : YT的类型为A | B | C,会被解析为(A extends U ? X : Y) | (B extends U ? X : Y) | (C extends U ? X : Y)

裸类型(naked type parameter):指类型参数没有被包装在其他类型里,比如没有被数组、元组、函数、Promise等等包裹,简而言之裸类型就是未经过任何其他类型修饰或包装的类型。

type T10 = TypeName<string | (() => void)>; // "string" | "function"
type T12 = TypeName<string | string[] | undefined>; // "string" | "object" | "undefined"
type T11 = TypeName<string[] | number[]>; // "object"
1
2
3

WARNING

与联合类型和交叉类型相似,条件类型不允许递归地引用自己。

extends运用在interfaceclass中是继承。type中是扩展,虽然也有继承的意思,但是作为条件类型,判断逻辑不同。

interface b {
  c: string;
  d: number;
}
interface e {
  c: string;
}
type a<T> = T extends e ? string : number;
type t = a<b>
//type t = string

let bbb:b = {
  c: '123',
  d: 123
}
let eee:e = {
  c: 'sdd',
}
// 虽然在定义eee时不能写除了c之外的属性 但是赋值的时候是可以的
eee = bbb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
最近更新: 2025年03月13日 17:49:47