目录
- 前言
- 常用 Utility Types 及其实现
- `Partial<T>`
- `Required<T>`
- `Readonly<T>`
- `Pick<T, K>`
- `Omit<T, K>`
- `Record<K, T>`
- `Exclude<T, U>`
- `Extract<T, U>`
- `NonNullable<T>`
- `ReturnType<T>`
- `InstanceType<T>`
- `Parameters<T>`
- `ConstructorParameters<T>`
- `Awaited<T>`
- 结语
前言
上一篇文章介绍了 typescript 类型体操中涉及到的基本概念,这篇文章我会将创建的utility Type进行实例讲解,并一一实现它。通过实践来深刻体会 , Utility Types 是一种特殊的类型,它们不是具体的值类型,而是可以对现有类型进行操作的类型。这些操作包括但不限于:选择属性、排除属性、从属性中提取类型等。
- TypeScript体操(一):从基础到进阶
Just Do It!
正文开始
,如果觉得文章对您有帮助,请帮我三连+订阅,谢谢
💖💖💖
常用 Utility Types 及其实现
TypeScript 提供了许多内置的 Utility Types, 下面我们只列举出了一些工作中常用的类型进行实现
Partial<T>
Partial<T>
将类型 T
的所有属性设置为可选。
-
使用实例:
interface User { id: number; name: string; age: number; } const updateUser = (user: Partial<User>) => { // 可以只传递部分属性 console.log(user); }; updateUser({ name: "张三" });
-
手写实现:
type MyPartial<T> = { [P in keyof T]?: T[P]; };
Required<T>
Required<T>
将类型 T
的所有属性设置为必选。
-
使用实例:
interface User { id: number; name: string; age: number; } const updateUser = (user: Required<User>) => { // 必须传递所有属性 console.log(user); }; updateUser({ id:1 , name: "张三", age:20 });
-
手写实现:
type MyRequired<T> = { [P in keyof T]: T[P]; };
Readonly<T>
Readonly<T>
使类型 T
的所有属性变为只读。
-
使用实例:
interface User { id: number; name: string; age: number; } const user: Readonly<User> = { id: 1, name: "张三", age: 20, }; // user.name = "李四"; // Error: name是自读属性, 不能进行赋值
-
手写实现:
type MyReadonly<T> = { readonly [P in keyof T]: T[P]; };
Pick<T, K>
Pick<T, K>
从类型 T
中选取部分属性,创建一个新的类型。
-
使用实例:
interface User { id: number; name: string; age: number; email: string; } type UserNameAndEmail = Pick<User, "name" | "email">; const user: UserNameAndEmail = { name: "张三", email: "zhangsan@example.com", };
-
手写实现:
type MyPick<T, K extends keyof T> = { [P in K]: T[P]; };
Omit<T, K>
Omit<T, K>
从类型 T
中排除部分属性,创建一个新的类型。
-
使用实例:
interface User { id: number; name: string; age: number; email: string; } type UserWithoutEmail = Omit<User, "email">; const user: UserWithoutEmail = { id: 1, name: "张三", age: 20, };
-
手写实现:
type MyOmit<T, K extends keyof any> = Pick<T, Exclude<keyof T, K>>; // 不依赖其他 type MyOmit<T, K> = { [Key in keyof T as Key extends K ? never : Key]: T[Key] }
Record<K, T>
Record<K, T>
创建一个类型,其键为 K
类型,值为 T
类型的字典。
-
使用实例:
type Role = "admin" | "user" | "guest"; interface User { id: number; name: string; } const users: Record<Role, User> = { admin: { id: 1, name: "管理员" }, user: { id: 2, name: "普通用户" }, guest: { id: 3, name: "访客" }, };
-
手写实现:
type MyRecord<K extends keyof any, T> = { [P in K]: T; };
Exclude<T, U>
Exclude<T, U>
从类型 T
中排除类型 U
的所有属性。
-
使用实例:
type T = "a" | "b" | "c"; type U = "a"; type Result = Exclude<T, U>; // "b" | "c"
-
手写实现:
type MyExclude<T, U> = T extends U ? never : T;
Extract<T, U>
Extract<T, U>
从类型 T
中提取出类型 U
的所有属性。
-
使用实例:
type T = "a" | "b" | "c"; type U = "a" | "c"; type Result = Extract<T, U>; // "a" | "c"
-
手写实现:
type MyExtract<T, U> = T extends U ? T : never;
NonNullable<T>
NonNullable<T>
从类型 T
中排除 null
和 undefined
。
-
使用实例:
type T = string | number | null | undefined; type Result = NonNullable<T>; // string | number
-
手写实现:
type MyNonNullable<T> = T extends null | undefined ? never : T;
ReturnType<T>
ReturnType<T>
提取函数类型 T
的返回类型。
-
使用实例:
function getUser(): { id: number; name: string } { return { id: 1, name: "张三" }; } type User = ReturnType<typeof getUser>; // { id: number; name: string }
-
手写实现:
type MyReturnType<T extends (...args: any) => any> = T extends ( ...args: any ) => infer R ? R : any;
InstanceType<T>
InstanceType<T>
提取构造函数类型 T
的实例类型。
-
使用实例:
class User { constructor(public id: number, public name: string) {} } type UserInstance = InstanceType<typeof User>; // User
-
手写实现:
type MyInstanceType<T extends new (...args: any) => any> = T extends new ( ...args: any ) => infer R ? R : any;
Parameters<T>
Parameters<T>
提取函数类型 T
的参数类型组成的元组。
-
使用实例:
function createUser(name: string, age: number) { return { name, age }; } type Params = Parameters<typeof createUser>; // [string, number]
-
手写实现:
type MyParameters<T extends (...args: any) => any> = T extends (...args: infer P) => any ? P : never;
ConstructorParameters<T>
ConstructorParameters<T>
提取构造函数类型 T
的参数类型组成的元组。
-
使用实例:
class User { constructor(public name: string, public age: number) {} } type Params = ConstructorParameters<typeof User>; // [string, number]
-
手写实现:
type MyConstructorParameters<T extends new (...args: any) => any> = T extends new ( ...args: infer P ) => any ? P : never;
Awaited<T>
该类型用于模拟 async 函数中的 await 操作,或者 promise 上的 .then() 方法,独特之处在于,它们通过递归展开 promise 的方式获取异步返回的结果。
如果 推断的类型 F 仍未函数类型,则继续递归F extends (value: infer V) => any ? Awaited<V> : never
-
使用实例:
type A = Awaited<Promise<string>>; // type A = string type B = Awaited<Promise<Promise<number>>>; // type B = number type C = Awaited<boolean | Promise<number>>; // type C = number | boolean
-
手写实现:
type MyAwaited<T> = T extends null | undefined ? T : T extends object & { then(onfulfilled: infer F): any; } ? F extends (value: infer V) => any ? MyAwaited<V> : never : T type A = MyAwaited<Promise<string>>; // type A = string type B = MyAwaited<Promise<Promise<number>>>; // type B = number type C = MyAwaited<boolean | Promise<number>>; // type C = number | boolean
结语
通过这篇文章,我们深入探讨了 TypeScript 中的 Utility Types 及其实现和应用。这些类型工具在实际开发中非常有用,能够帮助我们简化代码、提高类型安全性和可维护性。掌握这些技巧,能让你在处理复杂类型时游刃有余。希望这些内容对你有所帮助,并激发你在 TypeScript 类型体操方面的更多探索和实践。