TS08 TypeScript中的泛型工具

TypeScript中内置的泛型工具。

TS提供了很多泛型工具类型,可以帮助我们实现很多复杂的类型。之前对这块没有了解,很多复杂的类型都是自己来实现,其实借助这些工具可以很方便的实现

使用is进行类型收窄

1
2
3
function isUser(person: Person): person is User {
return person.type === 'user'
}

使用&进行属性的合并

使用&操作符可以实现属性合并

1
2
3
4
5
6
7
8
9
10
11
12
13
type User = {
name: string
}

type Admin = {
age: number
}

type Person = User | Admin;
// 此时 Person 可以包含 name 或者可以包含 age

type Staff = User & Admin;
// 此时 Staff 必须同时包含 name 和age

Partial<Type>

使用Partial<Type>将所有类型属性变成可选

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
interface Todo {
title: string;
description: string;
}

function updateTodo(todo: Todo, fieldsToUpdate: Partial<Todo>) {
return { ...todo, ...fieldsToUpdate };
}

const todo1 = {
title: "organize desk",
description: "clear clutter",
};

const todo2 = updateTodo(todo1, {
description: "throw out trash",
});

Partial的实现:

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

Required<Type>

Partial相反,将可选属性变为必选

1
2
3
4
5
6
7
8
9
10
interface Props {
a?: number;
b?: string;
}

const obj: Props = { a: 5 };

const obj2: Required<Props> = { a: 5 };
// 报错
// Property 'b' is missing in type '{ a: number; }' but required in type 'Required<Props>'.

Readonly<Type>

使用Readonly<Type>将类型设置为只读

1
2
3
4
5
6
7
8
9
10
11
interface Todo {
title: string;
}

const todo: Readonly<Todo> = {
title: "Delete inactive users",
};

todo.title = "Hello";
// 报错
// Cannot assign to 'title' because it is a read-only property.

Record<keys, Type>

使用Record生成的类型,包含keys对应的属性键名,键值为Type,常用来实现一种类型对另外一种类型的映射关系:

1
2
3
4
5
6
7
8
9
10
11
interface PageInfo {
title: string;
}

type Page = 'home' | 'about' | 'concat'';

const nav: Record<Page, PageInfo> = {
about: {title: 'about'},
contact: {title: 'contact'},
home: {title: 'home'},
}

Pick<Type, Keys>

使用Pick来在Type中拾取keys对应的属性

1
2
3
4
5
6
7
8
9
10
11
12
interface Todo {
title: string;
description: string;
completed: boolean;
}

type TodoPreview = Pick<Todo, "title" | "completed">;

const todo: TodoPreview = {
title: 'Clean Room',
completed: false
}

Omit<Type, keys>

Type中生成所有属性,并且移除key对应的属性

1
2
3
4
5
6
7
8
9
10
11
12
interface Todo {
title: string;
description: string;
completed: boolean;
}

type TodoPrview = Omit<Todo, 'description'>;

const todo: TodoPreview = {
title: "Clean room",
completed: false,
};

Exclude<Type, ExcludedUnion>

Type中移除ExcludedUnion中的所有类型(差集)

1
2
3
4
5
6
7
8
type T0 = Exclude<"a" | "b" | "c", "a">;
// type T0 = "b" | "c"

type T1 = Exclude<"a" | "b" | "c", "a" | "b">;
// type T1 = "c"

type T2 = Exclude<string | number | (() => void), Function>;
// type T2 = string | number

Extract<Type, Union>

生成TypeUnion的交集

1
2
3
4
5
type T0 = Extract<"a" | "b" | "c", "a" | "f">;
// type T0 = "a"

type T1 = Extract<string | number | (() => void), Function>;
// type T1 = () => void

NonNullable<Type>

生成不为nullundefined的类型

1
2
3
4
5
type T0 = NonNullable<string | number | undefined>;
// type T0 = string | number

type T1 = NonNullable<string[] | null | undefined>;
// type T1 = string[]

Parameters<Type>

生成对应的函数类型的Type的参数元组类型

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
declare function f1(arg: { a: number; b: string }): void;

type T0 = Parameters<() => string>;
// type T0 = []

type T1 = Parameters<(s: string) => void>;
// type T1 = [s: string]

type T2 = Parameters<<T>(arg: T) => T>;
// type T2 = [arg: unknown]

type T3 = Parameters<typeof f1>;
// type T3 = [arg: {
// a: number;
// b: string;
// }]

ReturnType<Type>

生成函数返回值对应的类型

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
declare function f1(): { a: number; b: string };

type T0 = ReturnType<() => string>;
// type T0 = string

type T1 = ReturnType<(s: string) => void>;
// type T1 = void

type T2 = ReturnType<<T>() => T>;
// type T2 = unknown

type T4 = ReturnType<typeof f1>;
// type T4 = {
// a: number;
// b: string;
// }

ThisParameterType<Type>

对于一个函数的this的类型,可以通过在参数中对进行声明:

1
2
3
function toHex(this: Number) {
return this.toString(16);
}

这时可以使用ThisParameterType<Type>返回this类型,如果函数没有声明this类型,那么会返回unknown

1
2
3
function numberToString(n: ThisParameterType<typeof toHex>) {
return toHex.apply(n);
}

参考

哆啦斯基周 wechat
我的公众号,看心情更新,欢迎订阅!