本文介绍了一些 TS 内置工具类型的用法及实现
Readonly & Mutable
type Person = { id: number; name: string; age: number };
type MyReadonly<T> = {
readonly [K in keyof T]: T[K];
};
type X1 = MyReadonly<Person>;
// {
// readonly id: number;
// readonly name: string;
// readonly age: number;
// }
type MyMutable<T> = {
-readonly [K in keyof T]: T[K];
};
type X9 = MyMutable<Readonly<Person>>;
// {
// id: number;
// name: string;
// age: number;
// }
注意:
Mutable并不是 TS 内置的函数-readonly []表示去掉属性前面的Readonly
Partial & Required
type Person = { id: number; name: string; age: number };
type MyPartial<T> = {
[K in keyof T]?: T[K];
};
type X2 = MyPartial<Person>;
// {
// id?: number;
// name?: string;
// age?: number;
// }
type MyRequired<T> = {
[K in keyof T]-?: T[K];
};
type X3 = MyRequired<Person>;
// {
// id: number;
// name: string;
// age: number;
// }
注意 -?,表示去掉属性的可选,变为必选
Exclude & Extract
type MyExclude<A, B> = A extends B ? never : A; type X5 = Exclude<1 | 2 | 3, 1 | 2>; // 3 type MyExtract<A, B> = A extends B ? A : never; type X6 = MyExtract<1 | 2 | 3, 2 | 4>; // 2
按照之前讲的乘法分配律,有如下理解过程:
type X5 = 1 | 2 | 3 extends 1 | 2 ? never : A type X5 = | 1 extends 1 | 2 ? never : 1 // never | 2 extends 1 | 2 ? never : 2 // never | 3 extends 1 | 2 ? never : 3 // 3 type X5 = never | never | 3 // 3
X6 的理解过程同 X5,这里不赘述
Omit & Pick
type Person = { id: number; name: string; age: number };
type MyOmit<T, Key extends keyof T> = Pick<T, Exclude<keyof T, Key>>;
// 或者
type MyOmit<T, Key extends keyof T> = {
[K2 in keyof T as (K2 extends Key ? never : K2)]: T[K2];
};
type X7 = MyOmit<Person, 'name' | 'age'>; // { id: number }
type MyPick<T, Key extends keyof T> = {
[K2 in Key]: T[K2];
};
type X8 = MyPick<Person, 'name' | 'age'>; // { name: string; age: number }
Key extends keyof T是一个泛型约束,约束所传的key必须包含在keyof T中,即必须是'id' | 'name' | 'age'的子集MyOmit的第二个写法中,集合K2 extends Key ? never : K2小于或等于集合K2 in keyof T,依旧遵循之前讲的类型兼容,类型小的可赋值给类型大的,查看实现思路
Record
type MyRecord<Key extends string | number | symbol, Value> = {
[k in Key]: Value;
};
type X4 = MyRecord<string, string>; // { [x: string]: string }
ReturnType
type MyReturnType<T extends (...args: any[]) => unknown> =
T extends (...args: any[]) => infer U
? U
: never
const fn = (v: boolean) => {
if (v) return 1
else return 2
}
type Result = MyReturnType<typeof fn> // 应推导出 "1 | 2"
Awaited
type MyAwaited<T extends PromiseLike<any>> = T extends PromiseLike<infer U> ? U extends PromiseLike<any> ? MyAwaited<U> : U : never; type Result = MyAwaited<Promise<string>> // string
PromiseLike 表示一个对象具有 then 方法,它可以像 Promise 一样使用链式调用。
PromiseLike 可以表示内置的 Promise 对象和第三方库或自定义实现的 thenable 对象,因此 PromiseLike 提供了更广泛的兼容性。
- 限制传入的类型必须是
PromiseLike - 使用
infer推导PromiseLike参数类型 - 如果推导类型仍为
PromiseLike,就循环调用MyAwaited - 否则直接返回推导类型
Parameters
type MyParameters<T extends (...args: any[]) => unknown> =
T extends (...args: infer P) => unknown
? P
: never;
const foo = (arg1: string, arg2: number): void => {}
type Result = MyParameters<typeof foo> // [arg1: string, arg2: number]
- 限制传入的类型必须是函数类型
- 使用
infer推导函数的参数类型 - 由于
...args本身已经是元组类型,因此infer P最终推导出的,也是元组类型
其他
这里推荐一个用于练习 TS 类型体操的 repo:TypeScript 类型体操姿势合集
看看别人的体操:
评论区
评论加载中...