TS中一些内置的工具函数实现和示例 Documentation - Utility Types
Partial
Partial<T>
将类型 T 中的所有属性转换为可选属性。
type Partial<T> = {
[P in keyof T]?: T[P];
};
首先通过 keyof T
拿到 T 的所有属性名,然后使用 in 进行遍历,将值赋给 P,最后通过 T[P]
取得相应的属性值的类。中间的 ? 号,用于将所有属性变为可选。
eg.
interface UserInfo {
id: string;
name: string;
}
// error:Property 'id' is missing in type '{ name: string; }' but required in type 'UserInfo'
const xiaoming: UserInfo = {
name: 'xiaoming'
}
**使用 Partial<T>**
type NewUserInfo = Partial<UserInfo>;
const xiaoming: NewUserInfo = {
name: 'xiaoming'
}
// => 相当于
interface NewUserInfo {
id?: string;
name?: string;
}
Partial<T>
有个局限性,就是只支持处理第一层的属性,如果我的接口定义是这样的
interface UserInfo {
id: string;
name: string;
fruits: {
appleNumber: number;
orangeNumber: number;
}
}
type NewUserInfo = Partial<UserInfo>;
// Property 'appleNumber' is missing in type '{ orangeNumber: number; }' but required in type '{ appleNumber: number; orangeNumber: number; }'.
const xiaoming: NewUserInfo = {
name: 'xiaoming',
fruits: {
orangeNumber: 1,
}
}
第二层以后就不会处理了,需要自己实现.
DeepPartial
type DeepPartial<T> = {
// 如果是 object,则递归类型
[U in keyof T]?: T[U] extends object
? DeepPartial<T[U]>
: T[U]
};
type PartialedWindow = DeepPartial<T>; // 现在T上所有属性都变成了可选啦
Required
将类型 T 中的所有属性转换为必选属性
type Required<T> = {
[P in keyof T]-?: T[P];
};
Partial 和 Required 的唯一差异是在索引类型签名处的可选修饰符,Partial 是 ?,即标记属性为可选,而 Required 则是 -?,相当于在原本属性上如果有 ? 这个标记,则移除它
// Partial 也可以显示 加上 +? 这种表示方法
type Partial<T> = {
[P in keyof T]+?: T[P];
};
eg.
interface PartialPerson {
name?: string;
age?: number;
}
type RequiredPerson = Required<PartialPerson>;
// RequiredPerson 的类型为 { name: string; age: number; }
Readonly
将类型 T 中的所有属性转换为只读属性
type Readonly<T> = {
readonly [P in keyof T]: T[P];
};
interface Person {
name: string;
age: number;
}
type ReadonlyPerson = Readonly<Person>;
// ReadonlyPerson 的类型为 { readonly name: string; readonly age: number; }
Record
Record<K extends keyof any, T>
创建一个具有指定属性类型 T 的对象,其属性由类型 K 中的所有属性组成。
K extends keyof any
即为键的类型,这里使用 extends keyof any
标明,
- 传入的 K 可以是单个类型,也可以是联合类型,
- 而 T 即为属性的类型
type Record<K extends keyof any, T> = {
[P in K]: T;
};
// 键名均为字符串,键值类型未知
type Record1 = Record<string, unknown>;
// 键名均为字符串,键值类型任意
type Record2 = Record<string, any>;
// 键名为字符串或数字,键值类型任意
type Record3 = Record<string | number, any>;
type Numbers = 'one' | 'two' | 'three';
type NumberMap = Record<Numbers, number>;
// NumberMap 的类型为 { one: number; two: number; three: number; }
interface PageInfo {
title: string
}
type Page = 'home' | 'about' | 'contact'
const x: Record<Page, PageInfo> = {
about: { title: 'about' },
contact: { title: 'contact' },
home: { title: 'home' }
}
type Test = Record<Page, PageInfo>
// 相当于 =>
// type Test = {
// home: PageInfo;
// about: PageInfo;
// contact: PageInfo;
// }
Pick
Pick<T, K>
从类型 T 中选择指定的一组属性 K 构造一个新的类型。 From T pick a set of properties K
type Pick<T, K extends keyof T> = {
[P in K]: T[P];
};
Pick,它接受两个泛型参数,T 即是我们会进行结构处理的原类型(一般是对象类型),而 K 则被约束为 T 类型的键名联合类型。
declare function pick<T, K extends keyof T>(obj: T, ...keys: K[]): Pick<T, K>;
interface Person {
name: string;
age: number;
address: string;
}
type PersonInfo = Pick<Person, 'name' | 'age'>;
// PersonInfo 的类型为 { name: string; age: number; }
interface Todo {
title: string;
description: string;
completed: boolean;
}
type TodoPreview = Pick<Todo, "title" | "completed">;
const todo: TodoPreview = {
title: "Clean room",
completed: false,
};
Pick 是保留这些传入的键,比如从一个庞大的结构中选择少数字段保留,需要的是这些少数字段,而 Omit 则是移除这些传入的键,也就是从一个庞大的结构中剔除少数字段,需要的是剩余的多数部分。
Omit
Omit<T, K extends keyof any>
从类型 T 中移除指定的属性 K 构造一个新的类型。
type Omit<T, K extends keyof any> = Pick<T, Exclude<keyof T, K>>;
interface Person {
name: string;
age: number;
address: string;
}
type PersonWithoutAddress = Omit<Person, 'address'>;
// PersonWithoutAddress 的类型为 { name: string; age: number; }
interface Todo {
title: string;
description: string;
completed: boolean;
}
type TodoPreview = Omit<Todo, "description">;
const todo: TodoPreview = {
title: "Clean room",
completed: false,
};
Exclude
Exclude<T, U>
从类型 T 中排除可以赋值给 U 的类型
type Exclude<T, U> = T extends U ? never : T;
type MyType = Exclude<string | number | boolean, boolean>;
// MyType 的类型为 string | number
type Tmp1 = Exclude<1, 2> // 1
type Tmp2 = Exclude<1 | 2, 2> // 1
type Tmp3 = Exclude<1 | 2 | 3, 2 | 3> // 1
type Tmp4 = Exclude<1 | 2 | 3, 2 | 4> // 1 | 3
// 注意,这里是分布式条件类型
type T0 = Exclude<'a' | 'b' | 'c', 'a'> // "b" | "c"
type T1 = Exclude<'a' | 'b' | 'c', 'a' | 'b'> // "c"
type T2 = Exclude<string | number | (() => void), Function> // string | number
Extract
Extract<T, U>
从类型 T 中提取可以赋值给 U 的类型
type Extract<T, U> = T extends U ? T : never;
type MyType = Extract<string | number | boolean, boolean>;
// MyType 的类型为 boolean
type T0 = Extract<"a" | "b" | "c", "a" | "f">; // "a"
type T1 = Extract<string | number | (() => void), Function>; // () =>void
ReturnType
**ReturnType<T> **
** **用于获取函数类型 T 的返回(值)类型
type ReturnType<T extends (...args: any[]) => any> = T extends (
...args: any[]
) => infer R
? R
: any
eg.
type Func = (value: number) => string;
const foo: ReturnType<Func> = "hello";
// ReturnType获取到 Func 的返回值类型为 string,
// 所以,foo 也就只能被赋值为字符串了
function greet(): string {
return "Hello";
}
type GreetReturnType = ReturnType<typeof greet>; // 结果为 string
NonNullable
**NonNullable<T>**
: 从类型 T 中移除 null 和 undefined
type NonNullable<T> = T extends null | undefined ? never : T;
// 最新版本 改为了这样了
type NonNullable<T> = T & {};
eg.
type MyType = string | null | undefined;
type NonNullableMyType = NonNullable<MyType>; // 结果为 string
type T0 = NonNullable<string | number | undefined>; // string | number
type T1 = NonNullable<string[] | null | undefined>; // string[]
Parameters
**Parameters<T>**
获取函数类型 T 的参数类型组成的元组类型
type Parameters<T extends (...args: any) => any> = T extends (
...args: infer P
) => any
? P
: never
eg.
function greet(name: string, age: number): void {
console.log(`Hello, ${name}! You are ${age} years old.`)
}
type GreetParameters = Parameters<typeof greet>
// 结果为 [string, number]
type A = Parameters<() => void> // []
type B = Parameters<typeof Array.isArray> // [any]
type C = Parameters<typeof parseInt> // [string, number | undefined]
type D = Parameters<typeof Math.max> // number[]