1. Partial<T>
:将类型 T
中的所有属性变为可选属性。
Partial<T>
是 TypeScript
中的一个工具类型,它可以将类型 T
中所有属性都变为可选属性,即将类型 T
转换为一个新的类型,该类型包含了 T
中所有属性,并且这些属性都是可选的。
下面是一个示例,展示了如何使用 Partial<T>
工具类型:
interface User {
name: string;
email: string;
age: number;
}
function updateUser(user: User, updatedData: Partial<User>) {
return { ...user, ...updatedData };
}
const user: User = { name: 'Alice', email: 'alice@example.com', age: 25 };
const updatedUser = updateUser(user, { age: 26 });
console.log(updatedUser); // { name: 'Alice', email: 'alice@example.com', age: 26 }
在上面的示例中,我们定义了一个名为 User
的接口,它包含了三个属性:name
、email
和 age
。然后,我们定义了一个名为 updateUser
的函数,它接受两个参数:user
和 updatedData
,分别表示要更新的用户对象和包含要更新的属性的对象。在函数中,我们使用对象展开运算符将 user
和 updatedData
合并成一个新的对象,并返回该对象。
在调用 updateUser
函数时,我们将 user 对象和一个包含 age 属性的对象传递给了函数。由于 age 属性是可选的,因此我们可以使用Partial<User>
将其转换为可选属性,而不是必需的属性。
通过使用 Partial<T>
工具类型,我们可以方便地将一个类型的所有属性都变为可选属性,从而更灵活地使用该类型。例如,当我们需要更新一个对象的部分属性时,就可以使用 Partial<T>
将这些属性变为可选属性,并传递一个包含要更新的属性的对象作为参数,从而更方便地实现对象更新。
2.Required<T>
:将类型T
中的所有可选属性变为必选属性.
Required<T>
是 TypeScript 中的一个工具类型,它可以将类型 T 中的所有可选属性变为必选属性,生成一个新的类型。
例如,我们有一个如下的接口:
interface User {
name?: string;
email?: string;
age?: number;
}
在上面的接口中,所有属性都是可选的。如果我们希望将它们变为必选属性,可以使用 Required<User>
工具类型:
type RequiredUser = Required<User>;
RequiredUser 的类型就是将 User 中所有可选属性变为必选属性的结果:
interface RequiredUser {
name: string;
email: string;
age: number;
}
这个工具类型的使用场景是当我们需要确保一个类型的所有属性都被赋值时。在 TypeScript 中,如果一个对象的某个属性为可选属性,那么它在赋值时可以被省略。但是有些情况下,我们希望确保一个对象的所有属性都被赋值,这时就可以使用 Required<T>
来将所有属性变为必选属性。
例如,在开发中,如果我们使用了一个第三方库,该库的类型定义中某些属性为可选属性,但是在我们的应用中,这些属性必须被赋值。这时,我们可以使用Required<T>
将所有属性变为必选属性,从而确保代码的正确性。
3.Pick<T,K>:
,他可以将类型T
中选择指定的属性K
,生成一个新的属性。
使用 Pick<T, K>
可以方便地从一个类型中选择需要的属性,生成一个新的类型,这个新类型只包含我们需要的属性。与直接定义一个新的接口相比,使用 Pick<T, K>
的好处是可以复用现有的接口定义,减少代码冗余,同时也可以更加清晰地表达出代码的意图。
例如,我们有一个如下的接口:
interface User {
id: number;
name: string;
email: string;
age: number;
}
如果我们只需要使用 User 中的 id 和 name 属性,可以使用 Pick<User, 'id' | 'name'>
来生成一个新的类型,它只包含 id 和 name 两个属性:
type UserIdAndName = Pick<User, 'id' | 'name'>;
生成的 UserIdAndName 类型是:
interface UserIdAndName {
id: number;
name: string;
}
在实际开发中,我们经常需要从一个复杂的接口中选择一部分属性,用于实现某些功能。使用Pick<T, K>
可以方便地从现有的接口中选择需要的属性,生成一个新的类型,避免了重复定义接口的冗余代码。同时,使用 Pick<T, K>
也可以更加清晰地表达代码的意图,使代码更加易读易懂。
4.Omit<T, K>:
从类型 T
中删除指定的属性 K
,生成一个新的类型。
使用 Omit<T, K>
可以方便地从一个类型中删除不需要的属性,生成一个新的类型,这个新类型只包含我们需要的属性。与直接定义一个新的接口相比,使用Omit<T, K>
的好处是可以复用现有的接口定义,减少代码冗余,同时也可以更加清晰地表达出代码的意图。
例如,我们有一个如下的接口:
interface User {
id: number;
name: string;
email: string;
age: number;
}
如果我们只不需要使用 email 属性,可以使用 Omit<User, ‘email’>
来生成一个新的类型,它不包含email 这个属性:
type UserIdAndName = Omit<User, 'email'>;
生成的 UserIdAndName 类型是:
interface UserIdAndName {
id: number;
name: string;
age: number;
}
在实际开发中,我们经常需要从一个复杂的接口中排除一部分属性,用于实现某些功能。使用 Omit<T, K>
可以方便地从现有的接口中排除指定的属性,生成一个新的类型,避免了重复定义接口的冗余代码。同时,使用 Omit<T, K>
也可以更加清晰地表达代码的意图,使代码更加易读易懂。
除此之外,Omit<T, K>
还可以用于对联合类型进行类型转换。例如,我们有一个联合类型 User | Admin,表示用户或管理员,其中 User 和 Admin 都包含 name 和 email 属性。如果我们想要将 User | Admin 转换为只包含 name 属性的类型,可以使用 Omit<User | Admin, 'email'>
来生成一个新的类型,它不包含 email 属性:
type UserNameOnly = Omit<User | Admin, 'email'> & { name: string };
这里我们将 Omit<User | Admin, 'email'>
和 { name: string } 进行交叉类型操作,生成一个新的类型 UserNameOnly,它只包含 name 属性,并且可以接受 User 和 Admin 类型的值。
5.Record<K, T>:
它可以生成一个类型为 T
的对象,其中属性名的类型为 K
具体来说,Record<K, T> 可以将一个类型 K 中的每个属性名映射为类型 T,生成一个对象类型,对象中每个属性名的类型都是 K,属性值的类型都是 T。
例如,我们可以使用 Record<string, number>
来生成一个对象类型,其中属性名为字符串类型,属性值为数字类型:
type NumberRecord = Record<string, number>;
const obj: NumberRecord = {
a: 1,
b: 2,
c: 3,
};
在上面的例子中,我们定义了一个名为 NumberRecord
的类型,它是一个由字符串类型为属性名,数字类型为属性值的对象类型。我们可以使用 NumberRecord
来定义一个对象 obj
,其中包含了三个属性,分别是 a、b、c
,它们的值分别为 1、2、3
。
除了字符串类型,我们还可以使用其他类型作为属性名,例如数字类型、枚举类型等。例如,我们可以使用 Record<number, string>
来生成一个对象类型,其中属性名为数字类型,属性值为字符串类型:
type StringRecord = Record<number, string>;
const obj: StringRecord = {
1: 'a',
2: 'b',
3: 'c',
};
在实际开发中,Record<K, T>
经常被用于定义一些映射表,将某个类型的属性名映射为另一个类型的属性值。例如,我们可以使用 Record<string, User>
来定义一个对象类型,其中属性名为字符串类型,属性值为 User
类型:
interface User {
id: number;
name: string;
email: string;
}
type UserMap = Record<string, User>;
在上面的例子中,我们定义了一个名为 UserMap
的类型,它是一个由字符串类型为属性名,User
类型为属性值的对象类型。我们可以使用 UserMap
来定义一个对象 userMap
,其中包含了多个用户信息,可以通过用户名来访问对应的用户信息:
const userMap: UserMap = {
'alice@example.com': {
id: 1,
name: 'Alice',
email: 'alice@example.com',
},
'bob@example.com': {
id: 2,
name: 'Bob',
email: 'bob@example.com',
},
'charlie@example.com': {
id: 3,
name: 'Charlie',
email: 'charlie@example.com',
},
};
const alice = userMap['alice@example.com'];
在上面的例子中,我们使用 Record<string, User>
来定义了一个名为 UserMap
的类型,它是一个由字符串类型为属性名,User
类型为属性值的对象类型。我们可以使用 UserMap
来定义一个对象 userMap
,其中包含了多个用户信息。
6.Exclude<T, U>:
它可以从类型 T 中排除掉类型 U 中包含的类型。
具体来说,Exclude<T, U>
可以将类型 T 中包含在类型 U 中的类型去掉,生成一个新的类型。这个新的类型包含了原来类型 T 中除了类型 U 中包含的类型之外的所有类型。
例如,我们可以使用 Exclude<string | number | boolean, boolean>
来生成一个新的类型,其中排除了布尔型的类型:
type MyType = Exclude<string | number | boolean, boolean>; // MyType 的类型为 string | number
在上面的例子中,我们定义了一个名为 MyType 的类型,它是一个排除了布尔型的类型 boolean 之后的类型。由于原来的类型包含了 string、number 和 boolean 三种类型,排除了 boolean 后,MyType 的类型为 string | number。
除了基本类型之外,Exclude<T, U>
也可以用于排除复杂类型中包含的类型。例如,我们可以使用 `` 来排Exclude<"a" | "b" | "c", "a" | "c">
除字符串类型中包含的 “a” 和 “c”:
type MyType = Exclude<"a" | "b" | "c", "a" | "c">; // MyType 的类型为 "b"
在上面的例子中,我们定义了一个名为 MyType 的类型,它是一个排除了字符串类型中包含的 “a” 和 “c” 之后的类型。由于原来的类型包含了 “a”、“b” 和 “c” 三个字符串,排除了 “a” 和 “c” 后,MyType 的类型为 “b”。
在实际开发中,Exclude<T, U>
经常被用于定义一些泛型类型,用于排除一些不需要的类型。例如,我们可以使用 Exclude<Todo, undefined>
来排除掉 Todo 类型中包含的 undefined 值:
interface Todo {
id: number;
title: string;
completed?: boolean;
}
type NonOptionalTodo = Exclude<Todo, undefined>;
在上面的例子中,我们定义了一个名为 Todo 的接口类型,它包含了 id、title 和 completed 三个属性,其中 completed 属性是可选的。我们可以使用 Exclude<Todo, undefined>
来定义一个名 NonOptionalTodo 的类型,它是一个排除了 Todo 类型中的 undefined 值之后的类型,也就是一个包含了 id、title 和 completed(必须存在)三个属性的类型。
7.Extract<T, U>:
用于从类型T
中提取出类型 U
中包含的类型。
具体来说,Extract<T, U>
返回一个新类型,它是将类型 T 中的那些能够赋值给类型 U 的值提取出来,构成新类型。
例如,我们定义了一个类型 MyType,它包含了字符串类型、数字类型和布尔类型:
type MyType = string | number | boolean;
然后我们可以使用 Extract
工具类型来从 MyType 类型中提取出字符串类型,生成一个新的类型 MyNewType:
type MyNewType = Extract<MyType, string>; // MyNewType 的类型为 string
在上面的例子中,MyNewType 的类型为 string,因为它提取了 MyType 中的字符串类型,其他类型都被排除了。
除了基本类型之外,Extract<T, U>
还可以用于提取复杂类型中包含的类型。例如,我们定义了一个对象类型 Person,它包含了 name 属性、age 属性和 gender 属性:
type Person = {
name: string;
age: number;
gender: string;
};
我们可以使用 Extract 工具类型来提取 Person 类型中的 name 属性:
type NameOnly = Extract<keyof Person, 'name'>; // NameOnly 的类型为 'name'
在上面的例子中,NameOnly 的类型为 ‘name’,因为它提取了 Person 类型中的 name 属性,其他属性都被排除了。
8.NonNullable<T>:
,它用于从类型 T 中排除 null 和 undefined 类型,返回一个新类型,新类型的值将不包含 null 和 undefined 类型。
例如,假设有一个变量 str,它的类型为 string | null | undefined,我们可以使用 NonNullable
工具类型将 null 和 undefined 类型排除,返回一个新类型 string:
const str: string | null | undefined = 'hello world';
const nonNullableStr: NonNullable<typeof str> = str; // nonNullableStr 的类型为 string
在上面的例子中,nonNullableStr 的类型为 string,因为它使用了 NonNullable<T>
工具类型,将 str 的类型中的 null 和 undefined 类型排除了。
除了可以用于普通的变量类型之外,NonNullable<T>
还可以用于函数类型的参数和返回值类型。例如,假设有一个函数 sum,它的参数类型为 number | null | undefined,返回值类型为 string | null | undefined,我们可以使用 NonNullable<T>
工具类型将参数类型和返回值类型中的 null 和 undefined 类型排除,生成一个新的函数类型:
function sum(x: number | null | undefined, y: number | null | undefined): string | null | undefined {
return x && y ? `${x + y}` : null;
}
const newSum: (x: NonNullable<number>, y: NonNullable<number>) => NonNullable<string> = sum;
在上面的例子中,我们将 sum 函数的参数类型和返回值类型中的 null 和 undefined 类型排除,并生成了一个新的函数类型 newSum,它的参数类型为 number,返回值类型为 string。
9.ReturnType<T>:
它用于获取函数类型 T 的返回值类型。如果 T 不是函数类型,将会产生一个编译错误。
例如,假设有一个函数 add,它接受两个 number 类型的参数并返回它们的和,我们可以使用 ReturnType<T>
工具类型来获取 add 函数的返回值类型:
function add(a: number, b: number): number {
return a + b;
}
type AddReturnType = ReturnType<typeof add>; // AddReturnType 的类型为 number
在上面的例子中,AddReturnType 的类型为 number,因为它使用了 ReturnType 工具类型,获取了 add 函数的返回值类型。
除了可以用于普通的函数类型之外,ReturnType<T>
还可以用于泛型函数类型。例如,假设有一个泛型函数 map,它接受一个函数 fn 和一个数组 arr,并将 fn 应用于 arr 的每个元素,返回一个新的数组,我们可以使用 ReturnType<T>
工具类型来获取 fn 函数的返回值类型:
function map<T, U>(arr: T[], fn: (value: T, index: number, array: T[]) => U): U[] {
return arr.map(fn);
}
type MapReturnType = ReturnType<typeof map>; // MapReturnType 的类型为 unknown
在上面的例子中,MapReturnType 的类型为 unknown,因为它使用了 ReturnType<T>
工具类型,获取了 map 函数的返回值类型,而 map 函数的返回值类型是由 fn 函数的返回值类型决定的,因此它是一个未知类型。
10.Parameters<T>:
它用于获取函数类型 T 的参数类型元组。如果 T 不是函数类型,将会产生一个编译错误。
例如,假设有一个函数 add,它接受两个 number 类型的参数并返回它们的和,我们可以使用 Parameters<T>
工具类型来获取 add 函数的参数类型元组:
function add(a: number, b: number): number {
return a + b;
}
type AddParametersType = Parameters<typeof add>; // AddParametersType 的类型为 [number, number]
在上面的例子中,AddParametersType 的类型为 [number, number],因为它使用了 Parameters<T>
工具类型,获取了 add 函数的参数类型元组。
除了可以用于普通的函数类型之外, Parameters<T>
还可以用于泛型函数类型。例如,假设有一个泛型函数 map,它接受一个函数 fn 和一个数组 arr,并将 fn 应用于 arr 的每个元素,返回一个新的数组,我们可以使用 Parameters<T>
工具类型来获取 fn 函数的参数类型元组:
function map<T, U>(arr: T[], fn: (value: T, index: number, array: T[]) => U): U[] {
return arr.map(fn);
}
type MapParametersType = Parameters<typeof map>; // MapParametersType 的类型为 [T[], (value: T, index: number, array: T[]) => U]
在上面的例子中,MapParametersType 的类型为 [T[], (value: T, index: number, array: T[]) => U],因为它使用了 Parameters<T>
工具类型,获取了 map 函数的参数类型元组,其中第一个元素是 arr 的类型,第二个元素是 fn 函数的类型。