# Typescript泛型工具
TS 内置了一些很强大的泛型工具,可以使我们可以很方便的进行类型定义。
# Partial<T>
-可选
将传入的属性变为可选项
interface IPeople {
title: string;
name: string;
}
const people: Partial<IPeople> = {
title: 'Delete inactive users'
};
2
3
4
5
6
7
8
源码:
type Partial<T> = {
[P in keyof T]?: T[P];
};
2
3
# Record<K,T>
-对象约束
类型参数K提供了对象属性名联合类型,类型参数T提供了对象属性的类型
// 将x, y 作为Person的key
type Peoples = Record<"x" | "y", string>;
const P: Peoples = {
x: {
name: '张三'
},
y: {
name: '李四'
}
}
2
3
4
5
6
7
8
9
10
11
源码:
通过 K extends keyof any
对泛型进行约束,约束在 any 的 key中, K可以是任意类型(联合类型、对象、枚举…),再通过映射对象类型 { P in K : T }
,将每一个属性成员转化为 T 类型
type Record<K extends keyof any, T> = {
[P in K]: T;
};
2
3
# Readonly<T>
-只读
把传入的类型变为只读状态
interface Person {
name: string;
age: number;
}
const p: Readonly<Person> = {
name: '张三',
age: 22
}
p.name = '李四'; // 无法分配到 "name" ,因为它是只读属性
2
3
4
5
6
7
8
9
10
11
源码:
与 Partial
实现原理类似,通过映射对象类型 { P in K : T }
方式遍历获取其所有属性成员,再统一设置为 readonly
type Readonly<T> = {
readonly [P in keyof T]: T[P];
};
2
3
# Required<T>
-必选
把传入的类型变为必选状态
interface Person {
name?: string;
age?: number;
}
const p: Required<Person> = {
name: '张三',
age: 22
}
2
3
4
5
6
7
8
9
源码:
与 Partial
实现原理类似,通过映射对象类型 { P in K : T }
方式遍历获取其所有属性成员, 再统一通过“-”
修饰符移除 “?”
修饰符,从而转变为必填状态
type Required<T> = {
[P in keyof T]-?: T[P];
};
// -? 表示必选
2
3
4
# Pick<T,K>
-指定属性范围
指定属性范围
interface IPerson {
name: string;
age: number;
}
type TP = Pick<IPerson, 'name'>;
const p: TP = {
age: 22, // 对象文字可以只指定已知属性,并且“age”不在类型“TP”中
name: '张三'
}
2
3
4
5
6
7
8
9
10
11
源码:
通过 K extends keyof T
进行泛型约束,将 K 被约束在 T 的key中,不能超出这个范围,再通过映射对象类型 { key in K : T[key] }
,来约束每一个属性成员。
type Pick<T, K extends keyof T> = {
[P in K]: T[P];
};
2
3
# Exclude<T,K>
-剔除属性(联合类型)
该工具类型能够从类型T中剔除所有可以赋值给类型U的类型
type T0 = Exclude<"a" | "b" | "c", "a">;
// 相当于 type T0 = "b" | "c"
type T1 = Exclude<"a" | "b" | "c", "a" | "b">;
// 相当于 type T1 = "c"
type T2 = Exclude<string | number | (() => void), Function>;
// 相当于 type T2 = string | number
2
3
4
5
6
7
8
注意:
// 条件类型作用于泛型内,且入参为联合类型(a|b)时,它们就会变成分布式的:
type Exclude<T, U> = T extends U ? never : T;
type Str = 'a' | 'b' | 'c';
type R = Exclude<'a' | 'd', Str>;
// 相当于
type R = Exclude<'a', Str> | Exclude<'d', Str>
// 也相当于
type R = never | 'd'
// 所以
type R = 'd'
//另外提一点,如果想避免这种行为,可以这样写;
type Exclude<T, U> = [T] extends [U] ? never : T;
//那
type Str = 'a' | 'b' | 'c';
type R = Exclude<'a' | 'd', Str>;
type R = never
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
源码:
表示如果 T
是 U
的子类返回 never
类型,如果不是返回 T
类型。 当 T
为联合类型的时候,它会自动分发条件。
type Exclude<T, U> = T extends U ? never : T;
# Extract<T,K>
-获取交叉属性
“Extract<T, U>”工具类型与“Exclude<T, U>”工具类型是互补的,它能够从类型T中获取所有可以赋值给类型U的类型
type T0 = Extract<'a' | 'b' | 'c', 'a' | 'f'>;
// 相当于 type T0 = 'a';
type T1 = Extract<string | (() => void), Function>;
// 相当于 type T1 = () => void;
type T2 = Extract<string | number, boolean>;
// 因为没有交集,相当于 type T2 = never;
2
3
4
5
6
7
8
源码:
与 Exclude<T, U>
实现方式类似
type Extract<T, U> = T extends U ? T : never;
# Omit<T,K>
-剔除属性(对象类型)
在 T 中删除对应的 K
interface IPerson {
name: string;
age: number;
}
type TP = Omit<IPerson, 'age'>;
const p: TP = {
name: '张三'
}
2
3
4
5
6
7
8
9
10
源码:
type Omit<T, K extends keyof any> = Pick<T, Exclude<keyof T, K>>;
# ReturnType<T>
-获取函数返回值类型
该工具类型能够获取函数类型T的返回值类型
// string
type T0 = ReturnType<() => string>;
// { a: string; b: number }
type T1 = ReturnType<() => { a: string; b: number}>;
2
3
4
5
源码:
type ReturnType<T extends (...args: any) => any> = T extends (...args: any) => infer R ? R : any;
// (...args: any) 表示可以提供any类型的任何数量的参数。因为存在数量未知的any参数,所以参数的类型是any的数组即 any[]。
// 第一个泛型表示 T 为一个有返回值的函数。
// 后面结果表示:如果 T 有返回值,结果为返回值 R ,否则返回 any。
2
3
4
infer:(推导泛型参数)
// infer 表示在 extends 条件语句中待推断的类型变量。
// 从返回值得到参数?
// 下面这个语句中infer P 表示待推断的函数参数(从T推导出P)。
type ParamType<T> = T extends (arg: infer P) => any ? P : T;
// 整句表示为:如果 T 能赋值给 (arg: infer P) => any,则结果是 (arg: infer P) => any 类型中的参数 P,否则返回为 T。
type numberPromise = Promise<number>;
type n = numberPromise extends Promise<infer P> ? P : never; // 推导出T是number
// 还有注意一点,infer 只能在 extends 的右边使用,infer P 的 P 也只能在条件类型为 True 的一边使用
2
3
4
5
6
7
8
# Parameters<T>
-获取函数参数类型
// a:string
type T0 = ReturnType<(a:string) => any>;
// [a: string; b: number]
type T1 = ReturnType<(a: string; b: number) => any>;
2
3
4
5
源码:
type Parameters<T extends (...args: any) => any> = T extends (...args: infer P) => any ? P : never;
# InstanceType<T>
-获取构造函数的类型
常见的使用有在 Vue 里获取子组件的类型
import MyModal from './MyModal.vue'
class C {
x = 0;
y = 0;
}
type T19 = InstanceType<typeof MyModal>; // MyModal extends Vue Component
type T20 = InstanceType<typeof C>; // C
type T21 = InstanceType<any>; // any
type T22 = InstanceType<never>; // any
type T23 = InstanceType<string>; // Error
type T24 = InstanceType<Function>; // Error
2
3
4
5
6
7
8
9
10
11
源码:
type InstanceType<T extends abstract new (...args: any) => any> = T extends abstract new (...args: any) => infer R ? R : any;
// abstract 关键字 定义为抽象类 后面必须跟 class 或 new 关键字
// new 关键字 字面量构造器签名 可以理解为 interface 它描述了构造函数的形状
2
3
# ConstructorParameters<T>
-获取构造函数参数
注意:是构造函数,即构造器中的入参,而非类对象。
class People {
name: string
age: number
constructor(name: string) {
this.name = name;
}
}
type IType = ConstructorParameters<typeof People>
// type IType = [name: string]
2
3
4
5
6
7
8
9
10
11
12
源码:
type ConstructorParameters<T extends abstract new (...args: any) => any> = T extends abstract new (...args: infer P) => any ? P : never;