typeof – 对象
一般我们都是先定义类型,再定义变量,使用typeof
可以得到变量的类型。
const options = {
a: 1
}
type Options = typeof options
keyof – 枚举类型(可以理解为keyof 对象类型
)
首先来看keyof
的定义:keyof
操作符可以用来枚举出一个对象中的所有key
值。
通俗来说,keyof
可以取出一个对象中的所有由key值组成的枚举类型
。
interface Person {
name: string;
age: number;
}
type K1 = keyof Person; // "name" | "age"
type K2 = keyof Person[]; // "length" | "toString" | "pop" | "push" | "concat" | "join"
type K3 = keyof { [x: string]: Person }; // string | number
可以看到使用let a: { [key in keyof Person]: string };
可以看到keyof Person
返回的枚举类型
。
in – 枚举类型
in
的定义是:用于遍历枚举类型
。
注意:in
只能遍历枚举类型
,不能遍历对象(keyof
遍历的是对象(类型))。
故而,Partial
(type Partial<T> = { [P in keyof T]?: T[P] };
)中,使用的是keyof
,若是改成[P in T]?: T[P]
则会报错,因为由T[P]
得知,T
为对象,而由[P] in T
得知,T
只能为string | number | symbol
,故而有冲突。
再看下面这个例子:
export enum IFlag {
A = 'A',
B = 'B',
C = "C",
D = "D",
}
export const OFlag: {[key in IFlag]?: string} = {
[IFlag.A]: '情景A',
[IFlag.B]: '情景B',
[IFlag.C]: '情景C',
[IFlag.D]: '情景D',
}
在项目中,使用此方式来管理页面中一些固定的键值,例如select下拉选项:
<select>
<option value="A">情景A</option>
<option value="B">情景B</option>
<option value="C">情景C</option>
<option value="D">情景D</option>
</select>
IFlag
枚举出所有的值,作为接口的入参,OFlag
配置页面的文案展示。
注意:IFlag
需定义为字符串枚举。
Partial – 对象类型
Partial
实现源码node_modules/typescript/lib/lib.es5.d.ts
type Partial<T> = { [P in keyof T]?: T[P] };
使用keyof T
拿到T
中的所有的属性值,[P in keyof T]
表示P
在keyof T
内,T[P]
取出对应属性的值,?
代表属性可选。
Required --对象类型
Required
实现源码node_modules/typescript/lib/lib.es5.d.ts。
type Required<T> = { [P in keyof T]-?: T[P] };
-?的作用就是把可选属性的可选性去掉,使该属性变成必选项,对应的还有+?(等价于?),作用与-?相反,是把属性变为可选项。
-
[P in keyof T]?: T[P]
:可选 -
[P in keyof T]+?: T[P]
:可选,等价于? -
[P in keyof T]-?: T[P]
:必选 -
[P in keyof T]: T[P]
:可选的依然可选,必选的依然必选
Exclude<T, U> – 枚举类型
从T
中去除T
与U
的交集后的类型。Exclude
实现源码node_modules/typescript/lib/lib.es5.d.ts。
type Exclude<T, U> = T extends U ? never : T;
例子:
type T = Exclude<1 | 2 | 3 | 4 | 5, 3 | 4>
Extract<T, U> – 枚举类型
从T
中提取T
与U
的交集类型。Extract
实现源码node_modules/typescript/lib/lib.es5.d.ts。
type Extract<T, U> = T extends U ? T : never;
例子:
type T = Extract<1 | 2 | 3 | 4 | 5, 3 | 4> // T = 3 | 4
Pick<T, K> – 对象类型
从T
中提取出T
与K
属性值相同的属性。Pick
实现源码node_modules/typescript/lib/lib.es5.d.ts。
Pick
与Extract
都有从T
中提取T
与K
相交的那部分,他们的区别在于Pick
作用于对象类型,返回的类型用于定义对象;Extract作用于枚举类型
,返回的类型用于定义枚举类型
变量。
type Pick<T, K extends keyof T> = { [P in K]: T[P]; };
例子:假设Person
类型中有name
、age
、sex
属性,当我们想生成一个新的类型只支持name
、age
时,则可使用Pick
:
interface Person {
name: string,
age: number,
sex: string,
}
let person: Pick<Person, 'name' | 'age'> = {
name: '小王',
age: 21,
}
Omit<T, K>(非内置)
从对象T
中剔除key
为K
中的属性。Omit
在TS
中没有内置,Omit
可以使用Pick
和Exclude
实现。
type Omit<T, K> = Pick<T, Exclude<keyof T, K>>
例子:
剔除Person
中的name
属性。
interface Person {
name: string,
age: number,
sex: string,
}
let person: Omit<Person, 'name'> = {
age: 18,
sex: '男'
}
Record<K, T>
将K
中所有的属性的值的类型转化为T
类型。Record
实现源码node_modules/typescript/lib/lib.es5.d.ts。
type Record<K extends keyof any, T> = { [P in K]: T; };
例子:
将Person
中的属性值的类型全部转为string
类型。
interface Person {
name: string,
age: number,
}
let person: Record<keyof Person, string> = {
name: '小王',
age: '12',
}
NonNullable<T> – 枚举类型
剔除T
为null
、undefined
的类型。NonNullable
实现源码node_modules/typescript/lib/lib.es5.d.ts。
type NonNullable<T> = T extends null | undefined ? never : T;
例子:
type T = NonNullable<string | string[] | null | undefined>; // string | string[]
ReturnType<T>
获取函数T
返回值的类型。ReturnType
实现源码node_modules/typescript/lib/lib.es5.d.ts。
type ReturnType<T extends (...args: any[]) => any> = T extends (...args: any[]) => infer R ? R : any;
infer R
相当于声明一个变量,接收传入函数的返回值类型。
例子:
type T1 = ReturnType<() => string>; // string
type T2 = ReturnType<(s: string) => void>; // void
Conditional Types(条件类型)
条件类型测试两种类型,然后根据该测试的结果选择其中一种。表现形式为T extends U ? X : Y
, 即如果类型T
是类型U
的子类型,则返回X
类型,否则返回Y
类型。
type NonNullable<T> = T extends null | undefined ? never : T;
通过一个简单的案例来进行理解,当泛型T
为string
类型的时候,那么B
为type B = "1"
,反之为type B = "2"
。可以看到同样的一个类型,因为传入的泛型T
不一样,结果自然而然的有了出入。
type B<T> = T extends string ? '1' : '2';
const a: B<string> = '1';
const b: B<number> = '1'; // 不能将类型"1"分配给类型"2"