Skip to main content

typescript 类型体操

Pick

从接口 IA 中提取出新的类型,索引是键名

interface IA {
a: string;
b: string;
c: string;
}

type typeB = Pick<IA, "a" | "b">;

const insB: typeB = {
a: "1",
b: "2",
};
// 在定义时限制extends,可以使传入T中不存在值时报错
type Pick<T, K extends keyof T> = {
[P in K]: T[P];
};

Omit

和 Pick 相反,排除不想要的值

type Exclude<T, U> = T extends U ? never : T;
type Omit<T, K extends keyof any> = Pick<T, Exclude<keyof T, K>>;

interface User {
name: string;
age: number;
addr: string;
}
const user: Omit<User, "name" | "addr"> = {
name: "licy",
age: 24,
}; // error: name 不在类型中

Partial

将一个对象中的 key 变成可选的

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

interface User {
name: "licy";
}
const user: Partial<User> = {}; // 没有错误,因为此时 name 是可选的

Required

和 Partial 相反,是将传入类型中可选的类型变成必填类型。

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

Readonly

将类型变成可读的,即不可修改。

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

Parameters

获取函数的参数

type Parameters<T extends (...args: any) => any> = T extends (
...args: infer P
) => any
? P
: never;

// 使用
type Fn = (name: string, age: number) => string;
type Params = Parameters<Fn>; // [name: string, age: number]

这里我们需要注意一下使用 infer 这个关键字。可以将这个关键理解成推断后的类型,并且它只可以用于 extends 的子句当中

ConstructorParameters

获取 class 构造方法的参数。

type ConstructorParameters<T extends abstract new (...args: any) => any> =
T extends abstract new (...args: infer P) => any ? P : never;

通过上面 TS 内部实现的高级类型可以发现,extends 和 infer 是特别重要的。extends 可以实现类似三元表达式的判断,判断传入的泛型是什么类型的,然后返回定义好的类型。infer 可以在判断是什么类型后,可以提取其中的类型并在子句中使用。和我们正常写代码一样,说明我们可以多个 extends 和 infer 进行嵌套使用,这样就可以把一个传入的泛型进行一次次分解

Uppercase

内部特殊实现 字符串转大写

Lowercase

内部特殊实现 字符串转小写

Capitalize

内部特殊实现 首字母大写

Uncapitalize

内部特殊实现 字母小写