TypeScript提供了一些非常好用的工具类型,能够配合我们更好的使用工具类型。
type 定义类型
类型别名:
type NumberOrString = number | string; // 定义类型
const name: NumberOrString = 'lichuyan';
keyof & typeof
keyof A : 返回A类型的所有key,组成联合类型。
typeof 变量: 得到变量B的类型,例如是A。
type AType = keyof typeof Data。得到D变量类型的所有key的联合类型。
[P in Keys] 映射类型
遍历key
type Keys = 'option1' | 'option2';
type Flags = { [K in Keys]: boolean };
等价于
type Flags = {
option1: boolean;
option2: boolean;
}
T[K]索引访问操作符
// 要确保类型变量 K extends keyof T
function getProperty<T, K extends keyof T>(o: T, name: K): T[K] {
return o[name]; // o[name] is of type T[K]
}
Record
Record 能够快速创建对象类型。 使用方式Record<K, V>,能够快速的为object创建统一的key和value类型。
因为V是string类型,但是age的值为number了。
Pick & Omit
针对interface
Pick:主要作用是从一组属性中拿出某个属性,并将其返回。--挑选属性
Omit:主要作用是从一组属性中排除某个属性,并将排除属性后的结果返回。--排除属性
Pick
从interface选取部分属性生成新type。
{
interface User {
name:string;
address:string;
}
type NameOnlyUser = Pick<User,'name'>;
let user: NameOnlyUser = {
name: 'lichuyan'
}
Omit<T, K extends keyof any>
注意:Omit<T, K> = Pick<T, Exclude<keyof T, K>>
用于剔除interface中的部分属性,生成新的type(类型)。
interface User {
name:string;
address:string;
}
type UserWithoutName = Omit<User, 'name'>; // 从User中去除,name属性。 去除多个,"name"| "address"
let user: UserWithoutName = {
}
Exclude & Extract
针对联合类型的操作
- Exclude:从一个联合类型中排除掉属于另一个联合类型的子集
- Extract:跟Exclude相反,从从一个联合类型中取出属于另一个联合类型的子集
Exclude(排除)
Exclude使用形式是Exclude<T, S>,如果T中的属性在S不存在那么就会返回。
接口 - keyof 可以用来取得一个对象接口的所有 key 值.
interface User {
name: string;
address: string;
order_date: string
}
interface User1 {
name: string;
odd: string
}
type OnlyAddress = Exclude<keyof User, keyof User1>; // name| address | order_date name | odd = address | order_date
Extract(排除)
举一反三,如果Exclude是取差集,那么Extract就是取交集。会返回两个联合类型中相同的部分
interface A {
show: boolean,
hidden: boolean,
status: string
}
interface B {
show: boolean,
name: string
}
type outPut = Extract<keyof A, keyof B>
实践经验
(1) 尽量减少重复代码
interface Person {
firstName: string;
lastName: string;
}
interface PersonWithBirthDate {
firstName: string;
lastName: string;
birth: Date;
}
相对于 Person 接口来说, PersonWithBirthDate 接口只是多了一个 birth 属性,其他的属性跟 Person 接口是一样的。那么如何避免出现例子中的重复代码呢?要解决这个问题,可以利用extends 关键字。
interface Person {
firstName: string;
lastName: string;
}
interface PersonWithBirthDate extends Person {
birth: Date;
}
(2) 提高类型复用性,放到types文件里,export出去
// ./src/model/user.ts
export interface userReq {
username: string
password: string
}
export interface userRes {
nickname: string
avatar?: string
age: number
}
(3) 高级小技巧
| S | T |
|---|---|
| 接口A、B一样多 | type B = A |
| A少、B多 | interface B extends A { XXX: string // 新添加的 } 或type C = A && B (交叉类型,A和B的并集) |
| A多、B少 | type B = Pick<A, 'name'>; // 从A中选择一些 或 type B = Omit<A, 'name'>; // 从A中抛弃一些 |