Skip to main content

高级类型

TypeScript提供了强大的类型系统,包括高级类型操作和类型编程能力。

交叉类型

基本交叉类型

typescript
1// 交叉类型
2interface Person {
3 name: string;
4 age: number;
5}
6
7interface Employee {
8 id: number;
9 department: string;
10}
11
12type PersonEmployee = Person & Employee;
13
14const person: PersonEmployee = {
15 name: "John",
16 age: 30,
17 id: 1,
18 department: "Engineering"
19};

函数交叉类型

typescript
1// 函数交叉类型
2type Function1 = (x: number) => number;
3type Function2 = (x: string) => string;
4
5type CombinedFunction = Function1 & Function2;
6
7// 注意:这种交叉类型在实际使用中可能没有意义
8// 因为一个函数不能同时接受number和string参数

联合类型

基本联合类型

typescript
1// 联合类型
2type StringOrNumber = string | number;
3
4function processValue(value: StringOrNumber): string {
5 if (typeof value === "string") {
6 return value.toUpperCase();
7 } else {
8 return value.toString();
9 }
10}
11
12// 联合类型数组
13type StringOrNumberArray = (string | number)[];
14
15const mixedArray: StringOrNumberArray = ["hello", 42, "world", 100];

字面量联合类型

typescript
1// 字面量联合类型
2type Status = "pending" | "success" | "error";
3
4function handleStatus(status: Status): string {
5 switch (status) {
6 case "pending":
7 return "Processing...";
8 case "success":
9 return "Completed successfully";
10 case "error":
11 return "An error occurred";
12 }
13}
14
15// 数字字面量联合类型
16type DiceRoll = 1 | 2 | 3 | 4 | 5 | 6;
17
18function rollDice(): DiceRoll {
19 return Math.floor(Math.random() * 6) + 1 as DiceRoll;
20}

类型守卫

typeof类型守卫

typescript
1// typeof类型守卫
2function processValue(value: string | number): string {
3 if (typeof value === "string") {
4 return value.toUpperCase();
5 } else {
6 return value.toString();
7 }
8}
9
10// 更复杂的typeof守卫
11function formatValue(value: string | number | boolean): string {
12 if (typeof value === "string") {
13 return value.toUpperCase();
14 } else if (typeof value === "number") {
15 return value.toFixed(2);
16 } else {
17 return value ? "true" : "false";
18 }
19}

instanceof类型守卫

typescript
1// instanceof类型守卫
2class Animal {
3 name: string;
4 constructor(name: string) {
5 this.name = name;
6 }
7}
8
9class Dog extends Animal {
10 bark(): string {
11 return "Woof!";
12 }
13}
14
15class Cat extends Animal {
16 meow(): string {
17 return "Meow!";
18 }
19}
20
21function makeSound(animal: Animal): string {
22 if (animal instanceof Dog) {
23 return animal.bark();
24 } else if (animal instanceof Cat) {
25 return animal.meow();
26 } else {
27 return "Unknown animal sound";
28 }
29}

自定义类型守卫

typescript
1// 自定义类型守卫
2interface Bird {
3 fly(): void;
4 layEggs(): void;
5}
6
7interface Fish {
8 swim(): void;
9 layEggs(): void;
10}
11
12function isFish(pet: Fish | Bird): pet is Fish {
13 return (pet as Fish).swim !== undefined;
14}
15
16function move(pet: Fish | Bird) {
17 if (isFish(pet)) {
18 pet.swim();
19 } else {
20 pet.fly();
21 }
22}
23
24// 使用in操作符的类型守卫
25function move2(pet: Fish | Bird) {
26 if ("swim" in pet) {
27 pet.swim();
28 } else {
29 pet.fly();
30 }
31}

条件类型

基本条件类型

typescript
1// 条件类型
2type NonNullable<T> = T extends null | undefined ? never : T;
3
4// 使用条件类型
5type T0 = NonNullable<string | number | null>; // string | number
6type T1 = NonNullable<string[] | null | undefined>; // string[]
7
8// 条件类型与联合类型
9type Diff<T, U> = T extends U ? never : T;
10type Filter<T, U> = T extends U ? T : never;
11
12type T2 = Diff<"a" | "b" | "c" | "d", "a" | "c" | "f">; // "b" | "d"
13type T3 = Filter<"a" | "b" | "c" | "d", "a" | "c" | "f">; // "a" | "c"

分布式条件类型

typescript
1// 分布式条件类型
2type ToArray<T> = T extends any ? T[] : never;
3
4type T4 = ToArray<string | number>; // string[] | number[]
5
6// 非分布式条件类型
7type ToArrayNonDist<T> = [T] extends [any] ? T[] : never;
8
9type T5 = ToArrayNonDist<string | number>; // (string | number)[]

条件类型推断

typescript
1// 条件类型推断
2type ReturnType<T> = T extends (...args: any[]) => infer R ? R : any;
3
4// 使用ReturnType
5function getUser() {
6 return { name: "John", age: 30 };
7}
8
9type User = ReturnType<typeof getUser>; // { name: string; age: number; }
10
11// 更复杂的条件类型推断
12type FirstIfString<T> = T extends [infer S, ...unknown[]]
13 ? S extends string
14 ? S
15 : never
16 : never;
17
18type T6 = FirstIfString<[string, number, boolean]>; // string
19type T7 = FirstIfString<[number, string, boolean]>; // never

映射类型

基本映射类型

typescript
1// 基本映射类型
2type Readonly<T> = {
3 readonly [P in keyof T]: T[P];
4};
5
6type Partial<T> = {
7 [P in keyof T]?: T[P];
8};
9
10type Required<T> = {
11 [P in keyof T]-?: T[P];
12};
13
14// 使用映射类型
15interface User {
16 id: number;
17 name: string;
18 email?: string;
19}
20
21type ReadonlyUser = Readonly<User>;
22type PartialUser = Partial<User>;
23type RequiredUser = Required<User>;

键重映射

typescript
1// 键重映射
2type Getters<T> = {
3 [P in keyof T as `get${Capitalize<string & P>}`]: () => T[P];
4};
5
6type UserGetters = Getters<User>;
7// 等价于:
8// {
9// getId: () => number;
10// getName: () => string;
11// getEmail: () => string | undefined;
12// }
13
14// 过滤键
15type RemoveKindField<T> = {
16 [P in keyof T as Exclude<P, "kind">]: T[P];
17};
18
19interface Circle {
20 kind: "circle";
21 radius: number;
22}
23
24type KindlessCircle = RemoveKindField<Circle>; // { radius: number; }

条件映射类型

typescript
1// 条件映射类型
2type EventConfig<T extends string> = {
3 [K in T]: { event: K; data: any };
4};
5
6type UserEvents = "click" | "hover" | "submit";
7type UserEventConfig = EventConfig<UserEvents>;
8
9// 等价于:
10// {
11// click: { event: "click"; data: any };
12// hover: { event: "hover"; data: any };
13// submit: { event: "submit"; data: any };
14// }

模板字面量类型

基本模板字面量类型

typescript
1// 模板字面量类型
2type EmailLocaleIDs = "welcome_email" | "email_heading";
3type FooterLocaleIDs = "footer_title" | "footer_sendoff";
4
5type AllLocaleIDs = `${EmailLocaleIDs | FooterLocaleIDs}_id`;
6
7// 等价于:
8// "welcome_email_id" | "email_heading_id" | "footer_title_id" | "footer_sendoff_id"
9
10// 模板字面量类型推断
11type PropEventSource<T> = {
12 on(eventName: `${string & keyof T}Changed`, callback: (newValue: any) => void): void;
13};
14
15declare function makeWatchedObject<T>(obj: T): T & PropEventSource<T>;
16
17const person = makeWatchedObject({
18 firstName: "Saoirse",
19 lastName: "Ronan",
20 age: 26
21});
22
23person.on("firstNameChanged", (newValue) => {
24 console.log(`firstName was changed to ${newValue}!`);
25});

模板字面量类型操作

typescript
1// 模板字面量类型操作
2type Uppercase<S extends string> = intrinsic;
3type Lowercase<S extends string> = intrinsic;
4type Capitalize<S extends string> = intrinsic;
5type Uncapitalize<S extends string> = intrinsic;
6
7// 使用这些内置类型
8type T8 = Uppercase<"hello">; // "HELLO"
9type T9 = Lowercase<"WORLD">; // "world"
10type T10 = Capitalize<"hello">; // "Hello"
11type T11 = Uncapitalize<"Hello">; // "hello"

实用工具类型

内置工具类型

typescript
1// Partial<T>
2interface Todo {
3 title: string;
4 description: string;
5}
6
7type PartialTodo = Partial<Todo>;
8// 等价于:
9// {
10// title?: string;
11// description?: string;
12// }
13
14// Required<T>
15type RequiredTodo = Required<Todo>;
16// 等价于:
17// {
18// title: string;
19// description: string;
20// }
21
22// Readonly<T>
23type ReadonlyTodo = Readonly<Todo>;
24// 等价于:
25// {
26// readonly title: string;
27// readonly description: string;
28// }
29
30// Pick<T, K>
31type TodoPreview = Pick<Todo, "title">;
32// 等价于:
33// {
34// title: string;
35// }
36
37// Omit<T, K>
38type TodoInfo = Omit<Todo, "completed" | "createdAt">;
39// 等价于:
40// {
41// title: string;
42// description: string;
43// }

条件工具类型

typescript
1// Exclude<T, U>
2type T0 = Exclude<"a" | "b" | "c", "a">; // "b" | "c"
3type T1 = Exclude<string | number | (() => void), Function>; // string | number
4
5// Extract<T, U>
6type T2 = Extract<"a" | "b" | "c", "a" | "f">; // "a"
7type T3 = Extract<string | number | (() => void), Function>; // () => void
8
9// NonNullable<T>
10type T4 = NonNullable<string | number | null | undefined>; // string | number
11
12// ReturnType<T>
13type T5 = ReturnType<() => string>; // string
14type T6 = ReturnType<(s: string) => void>; // void
15type T7 = ReturnType<<T>() => T>; // unknown
16
17// InstanceType<T>
18class C {
19 x = 0;
20 y = 0;
21}
22
23type T8 = InstanceType<typeof C>; // C
24type T9 = InstanceType<any>; // any
25type T10 = InstanceType<never>; // never

高级工具类型

typescript
1// ThisType<T>
2interface ObjectDescriptor<D, M> {
3 data?: D;
4 methods?: M & ThisType<D & M>;
5}
6
7declare function makeObject<D, M>(desc: ObjectDescriptor<D, M>): D & M;
8
9let obj = makeObject({
10 data: { x: 0, y: 0 },
11 methods: {
12 moveBy(dx: number, dy: number) {
13 this.x += dx; // 强类型化
14 this.y += dy; // 强类型化
15 }
16 }
17});
18
19// ThisParameterType<T>
20function toHex(this: Number) {
21 return this.toString(16);
22}
23
24type T11 = ThisParameterType<typeof toHex>; // Number
25
26// OmitThisParameter<T>
27type T12 = OmitThisParameter<typeof toHex>; // () => string

类型推断

类型推断基础

typescript
1// 类型推断
2let x = 3; // 推断为 number
3let y = "hello"; // 推断为 string
4let z = [1, 2, 3]; // 推断为 number[]
5
6// 上下文类型推断
7window.onmousedown = function(mouseEvent) {
8 console.log(mouseEvent.button); // 正确
9};
10
11// 最佳公共类型推断
12let x2 = [0, 1, null]; // 推断为 (number | null)[]
13let x3 = [0, 1, null, "hello"]; // 推断为 (number | null | string)[]

类型推断和泛型

typescript
1// 泛型类型推断
2function identity<T>(arg: T): T {
3 return arg;
4}
5
6let output = identity("myString"); // 推断为 string
7let output2 = identity(123); // 推断为 number
8
9// 约束类型推断
10function getProperty<T, K extends keyof T>(obj: T, key: K) {
11 return obj[key]; // 推断返回类型为 T[K]
12}
13
14let x = { a: 1, b: 2, c: 3, d: 4 };
15getProperty(x, "a"); // 推断为 number
16getProperty(x, "m"); // 错误!

类型编程

递归类型

typescript
1// 递归类型
2type JsonValue =
3 | string
4 | number
5 | boolean
6 | null
7 | JsonValue[]
8 | { [key: string]: JsonValue };
9
10// 递归条件类型
11type DeepReadonly<T> = {
12 readonly [P in keyof T]: T[P] extends object
13 ? T[P] extends Function
14 ? T[P]
15 : DeepReadonly<T[P]>
16 : T[P];
17};
18
19interface NestedObject {
20 a: number;
21 b: {
22 c: string;
23 d: {
24 e: boolean;
25 };
26 };
27}
28
29type DeepReadonlyNested = DeepReadonly<NestedObject>;

类型级编程

typescript
1// 类型级编程 - 数字运算
2type Length<T extends readonly any[]> = T["length"];
3
4type T13 = Length<[1, 2, 3]>; // 3
5
6// 类型级编程 - 字符串操作
7type StringLength<S extends string> = S extends `${infer First}${infer Rest}`
8 ? StringLength<Rest> extends infer Length
9 ? Length extends number
10 ? [First, ...(Length extends 0 ? [] : [Length])]
11 : never
12 : never
13 : [];
14
15type T14 = StringLength<"hello">; // ["h", "e", "l", "l", "o"]
16
17// 类型级编程 - 条件逻辑
18type If<C extends boolean, T, F> = C extends true ? T : F;
19
20type T15 = If<true, "yes", "no">; // "yes"
21type T16 = If<false, "yes", "no">; // "no"

参与讨论