TypeScript 常用类型总结

TypeScript 内置了一些较常用的类型,这些类型似于高阶函数,输入一个类型,返回一个新的类型:

1
2
// 伪代码
type Type2 = Func(Type1)

下面我们介绍下这些常用的类型以及写几个我们自己的常用类型。

Readonly<T>

将 T 中的属性变为只读(内置)。

1
type Readonly<T> = { readonly [P in keyof T]: T[P] };

##Required<P>

将 P 中的属性变为必选(内置)。

1
2
type Required<T> = { [P in keyof T]-?: T[P] };
type Person2 = Required<{ name: string; age?: number }>; // {name: string; age: number}

Required2<T, P>

将 T 中的 P 属性变为必选(非内置)。

1
2
3
4
5
6
7
// 不包含需要可选属性的对象 & 只包含可选值得对象并进行可选操作
type Required2<T, P extends keyof T> = Omit<T, P> & Required<Pick<T, P>>;
type Person2 = Required2<
{ name: string; age?: number; school?: string },
"age"
>;
// {name: string; age: number; school?: string}

Partial<T>

将 T 中的属性变成可选(内置)。

1
2
type Partial<T> = { [P in keyof T]?: T[P] };
type PersonPartial = Partial<Person>; // {name?:string; age?:number}

Partial2<T, P>

将 T 中 P 属性变为可选(非内置)。

1
2
3
// 不包含需要可选属性的对象 & 只包含可选值得对象并进行可选操作
type Partial2<T, P extends keyof T> = Omit<T, P> & Partial<Pick<T, P>>;
type Person2 = Partial2<Person, "age">; // {name: string; age?: number}

Pick<T, K>

从 T 中选择出 K 属性(内置)组成新的对象。

1
2
type Pick<T, K extends keyof T> = { [P in K]: T[P] };
type Person2 = Pick<Person, "name">; // {name: string}

Record<K, T>

用属性为 K 的类型,值为 T 的类型生成新的对象(内置)。

1
2
3
4
5
type Record<K extends keyof any, T> = {
[P in K]: T;
};

Type Person = Record<'name'|'school', string> // {name: string; school: string}

Omit<T, K>

从对象 T 中排除属性是 K 的属性(没有内置)。

1
2
Omit<T, K> = Pick<T, Exclude<keyof T, K>>
type Person2 = Omit<Person, 'age'> // {name: string}

Exclude<T, U>

从 T 中排除是 U 的类型(内置)。

1
2
3
type Exclude<T, U> = T extends U ? never : T;

type T00 = Exclude<"a" | "b" | "c" | "d", "a" | "c" | "f">; // "b" | "d"·

Extract<T, U>

从 T 中提取属于 U 的类型(内置)。

1
2
type Extract<T, U> = T extends U ? T : never;
type T01 = Extract<"a" | "b" | "c" | "d", "a" | "c" | "f">; // "a" | "c"

[keyof T]

获取 value

获取值为 function 类型的 key。

1
2
3
type FunctionPropertyNames<T> = {
[K in keyof T]: T[K] extends Function ? K : never
}[keyof T];
1
type PersonValue = Person[keyof Person]; // "string" | "number"

Filter<T, P>

过滤 T 中值类型为 P 类型的 key 组成新的对象(非内置)。

1
2
3
4
5
type FilterType<T, P> = { [K in keyof T]: T[K] extends P ? K : never }[keyof T];
type Filter<T, P> = Pick<T, FilterType<T, P>>;

// 过滤所有 value 为 string 类型的 key
type PersonStr = Filter<Person, String>; // {name: string}

这里利用了条件类型(Conditional Types),使用条件类型可以完成更多操作。
比如我们要让一个对象所有的属性变成可选,包括深层次的对象引用:

1
2
3
4
5
6
7
type Child = {
name: string;
};
type TP = {
name: string;
children: Child[];
};
1
2
3
4
5
6
7
type PartialDeep<T> = {
[K in keyof T]?: T[K] extends (infer U)[]
? PartialDeep<U>[]
: T[k] extends object
? PartialDeep<T[K]>
: T[K]
};
1
2
type PartialTP = PartialDeep<TP>;
const parent: PartialTP = { children: [{}] }; // 所有的属性都为可选值,包括children里的对象

Mutable<T>

T 变成可写。

1
type Mutable<T> = { -readonly [P in keyof T]: T[P] };

ReturnType<T>

获取函数返回类型(内置)。

1
2
3
4
5
6
7
type ReturnType<T extends (...args: any) => any> = T extends (
...args: any
) => infer R
? R
: any;
type TFunc = (...args: any[]) => string;
type Ret = ReturnType<TFunc>; // string

NonNullable<T>

排除 null 和 undefined

1
2
3
4
5
6
7
8
9
type NonNullable<T> = T extends null | undefined ? never : T;

type Person = {
name: string | undefined;
age: number;
};

type NonNull<T> = { [K in keyof T]: NonNullable<T[K]> };
type PersonNonNull = NonNull<Person>; // {name: string; age: number}

keyof 关键字

keyof T 用来获取 T 中的属性名。

获取对象的所有属性:

1
2
type GetAllProps<T> = { [K in keyof T]: K }[keyof T];
type PersonProps = GetAllProps<Person>; // "name" | "age"

获取对象的所有 value 类型:

1
2
type GetAllValues<T> = T[keyof T];
type PersonValues = GetAllValues<Person>; // string | number

获取数组类型中所有的类型:

1
2
3
type Info = [string, number];
// 返回了数组的原型方法类型
type InfoValues = GetAllValues<Info>; //type InfoValues = string | number | (() => string)...

显然返回方法类型不是我们想要的,需要把它们过滤掉:

1
2
3
4
5
6
type ArrValueOf<T extends any[]> = T[(keyof T) extends Number
? (keyof T)
: never];

type Info = [string, number];
type InfoValues = ArrValueOf<Info>; // string | number
1
2
3
type GetAllArrValues<T extends any[]> = T[(keyof T) extends Number
? (keyof T)
: never];

infer 关键字

infer 关键字常被用来获取函数返回类型。
我们看以下 ReturnType 的定义:

1
2
3
4
5
type ReturnType<T extends (...args: any) => any> = T extends (
...args: any
) => infer R
? R
: any;

infer 关键字的含义是:获得 infer 所在位置的推断类型并赋值给 R。上例中 infer 的位置刚好是在函数的返回值,所以 R 就为函数返回类型了。

下面我们利用 infer 来获取任意一个函数参数类型:

1
2
type ArgumentsType<T extends (...args: infer AType) => any> = AType;
// 'infer' declarations are only permitted in the 'extends' clause of a conditional type.ts(1338)

上边这种写法是不允许的,因为 infer 只允许在 extends 的条件判断类型中使用,所以我们要强行构造一个条件判断:

1
2
3
4
5
type ArgumentsType<T extends (...args: any) => any> = T extends (
...args: infer TArgs
) => any
? TArgs
: never;
1
2
type Fn = (a: string, b: number) => string;
type ArgFn = ArgumentsType<Fn>; // [string, number]

is 关键字

is 关键字 常用语类型断言:something is Type。这个在判断联合类型时经常用到。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
interface Bird {
fly(str: string): string;
layEggs(): boolean;
}

interface Fish {
swim();
layEggs();
}

function isBird(pet: Fish | Bird): pet is Bird {
return (<Bird>pet).fly !== undefined;
}

function petPlay(pet: Fish | Bird) {
if (isBird(pet)) {
const aa = pet.fly("asdf");
}
}