TypeScript 类型工具

对象和​对象类型

对象(Object)​​ 和 ​对象类型(Object Type)​​ 在 TypeScript 中有本质区别,且分别属于 ​值空间(Value Space)​​ 和 ​类型空间(Type Space)​。

关键字 keyof

keyof 是 TypeScript 特有的关键字。获取对象类型所有键的联合类型,常用于类型安全访问属性。

关键字 typeof

typeof 在 TypeScript 中用于将对象转为对象类型。推导变量或表达式的静态类型,常用于类型复用。

条件类型

type AAA = { name: string; age: number };
type BBB = { name: string };

type CCC = BBB extends AAA ? true : false; //false

检查类型 BBB 是否可以赋值给类型 AAA(即 BBB 是否是 AAA 的子类型,或结构兼容)。

type AAA = string | boolean | number;
type BBB = string | number;

type CCC = BBB extends AAA ? true : false; //true | false
type CCC = [BBB] extends [AAA] ? true : false; //false
  • BBB extends AAA ? true : false: 这是直接的条件类型判断,当 BBB是联合类型时,会进行分布式条件类型判断。
  • [BBB] extends [AAA] ? true : false: 这里使用了包裹类型 [BBB],这会阻止分布式条件类型。

Exclude ,从 AAA(联合类型)中删除 BBB(联合类型)

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

type AAA = string | number;
type BBB = string;

const XXX: EXCLUDE<AAA, BBB> = 100;
const YYY: Exclude<AAA, BBB> = 100;

Extract ,从 AAA(联合类型)中保留 BBB(联合类型)

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

type AAA = string | number;
type BBB = number | boolean;

const XXX: EXTRACT<AAA, BBB> = 100;
const YYY: Extract<AAA, BBB> = 100;

Pick ,从 AAA(对象类型) 中挑选出 BBB(联合类型)组成新的类型

type PICK<T, U extends keyof T> = { [P in U]: T[P] };

type AAA = { name: string; age: number; skill: string };

const XXX: PICK<AAA, 'name' | 'age'> = { name: 'Alrcly', age: 18 };
const YYY: Pick<AAA, 'name' | 'age'> = { name: 'Alrcly', age: 18 };

TypeScript 的映射类型

语法是 [P in U]: T[P] 这种

关键字 extends 的作用取决于它所处的上下文

条件类型判断:当 extends 出现在类型定义的条件部分时,它用于条件类型判断。形式是T extends U ? X : Y。这种情况下,它会检查类型 T 是否可以赋值给类型 U(即 T 是否是 U 的子类型)。如果可以,则类型为 X,否则类型为 Y。

泛型约束:当 extends 出现在泛型类型定义中时,它用于约束泛型的类型。形式是 <T extends U>。这种情况下,它表示泛型类型 T 必须是类型 U 或 U 的子类型。这可以限制泛型可以接受的类型范围,并允许在泛型类型中使用特定于该类型的属性或方法。

Omit ,从 AAA(对象类型) 中过滤掉 BBB(联合类型)组成新的类型

type OMIT<T, U> = Pick<T, { [K in keyof T]: K extends U ? never : K }[keyof T]>;

type AAA = { name: string; age: number; city: string };

type xxx = OMIT<AAA, 'name' | 'age'>;
type YYY = Omit<AAA, 'name' | 'age'>;

关键的中间形态,这个中间形态是 ​对象类型 而不是 对象

{"a": never; "b": never; "c": "c"}["a" | "b" | "c"] == {对象类型}[联合类型]

当通过 ["a" | "b" | "c"] 访问对象类型的属性时,TypeScript 会将所有键对应的属性类型进行联合。

Partial ,用于将 AAA (对象类型) 的全部属性设置为可选

type PARTIAL<T> = { [P in keyof T]?: T[P] };

type AAA = { name: string; age: number };

const XXX: PARTIAL<AAA> = { name: 'Alrcly' };
const YYY: Partial<AAA> = { name: 'Alrcly' };

Record ,用于快速定义 AAA (对象类型) 的对象类型

type RECORD<K extends string | number | symbol, V> = { [P in K]: V };

type XXX = RECORD<'name' | 'age', string | number>;
type XX = {
  name: string | number;
  age: string | number;
};

type YYY = Record<string, number>;
type YY = {
  [x: string]: number;
};

TypeScript 中的索引签名

type AAA = {
  [x: string]: string;
};

let AA: AAA = {
  aaa: 'aaa',
  bbb: 'bbb',
  ccc: 'ccc',
};

交叉类型在 Typescript 中的使用

将 AAA(对象类型) 和 BBB(对象类型)组成新的对象类型

type AAA = { name: string };
type BBB = { age: number; name: string };

type CCC = AAA & Pick<BBB, 'age'>;

let CC: CCC = { age: 30, name: 'Alrcly' };