1. keyof 和 in
1.1 keyof
keyof 与 Object.keys 略有相似,只不过 keyof 取 interface 的键
interface Point {
x: number;
y: number;
}
// type keys = "x" | "y"
type keys = keyof Point;
假设有一个 object 如下所示,我们需要使用 typescript 实现一个 get 函数来获取它的属性值
const data = {
a: 3,
hello: 'world'
}
function get(o: object, name: string) {
return o[name]
}
我们刚开始可能会这么写,不过它有很多缺点
- 无法确认返回类型:这将损失 ts 最大的类型校验功能
- 无法对 key 做约束:可能会犯拼写错误的问题
这时可以使用 keyof 来加强 get 函数的类型功能
function get<T extends object, K extends keyof T>(o: T, name: K): T[K] {
return o[name]
}
1.2 in
in 则可以遍历枚举类型, 例如
type Keys = "a" | "b"
type Obj = {
[p in Keys]: any
} // -> { a: any, b: any }
keyof 产生枚举类型, in 使用枚举类型遍历, 所以他们经常一起使用, 看下 Partial 源码
type Partial<T> = { [P in keyof T]?: T[P] };
上面语句的意思是 keyof T 拿到 T 所有属性名, 然后 in 进行遍历, 将值赋给 P, 最后 T[P] 取得相应属性的值.
2. Required & Partial & Pick
type Required<T> = {
[P in keyof T]-?: T[P];
};
type Partial<T> = {
[P in keyof T]?: T[P];
};
type Pick<T, K extends keyof T> = {
[P in K]: T[P];
};
interface User {
id: number;
age: number;
name: string;
};
// 相当于: type PartialUser = { id?: number; age?: number; name?: string; }
type PartialUser = Partial<User>
// 相当于: type PickUser = { id: number; age: number; }
type PickUser = Pick<User, "id" | "age">
这几个类型已内置在 Typescript中
3. Condition Type
类似于 js 中的 三目 运算符,可以使用它扩展一些基本类型
T extends U ? X : Y
type isTrue<T> = T extends true ? true : false
// 相当于 type t = false
type t = isTrue<number>
// 相当于 type t = false
type t1 = isTrue<false>
4. Exclude
Exclude 将某个类型中属于另一个的类型移除掉。
type Exclude<T, U> = T extends U ? never : T;
平常日剔除休息日就是工作日
// 一周(平常日)
type Weekday = 'Monday' | 'Tuesday' | 'Wednesday' | 'Thursday' | 'Friday' | 'Saturday' | 'Sunday';
// 休息日
type DayOff = 'Saturday' | 'Sunday';
// 工作日
type WorkDay = Exclude<Weekday, DayOff>;
const day: WorkDay = 'Monday';
5. Extract
和 Exclude 相反,提取共同的类型:
type Extract<T, U> = T extends U ? T : never;
提取重叠的时间即可:
// 休息日
type DayOff = 'Saturday' | 'Sunday';
// 会员日
type VipDay = 'Sunday' | 'Monday';
// 等价与 type DoubleDiscountDay = 'Sunday';
type DoubleDiscountDay = Extract<DayOff, VipDay>;
const day0: DoubleDiscountDay = 'Sunday'; // Success
const day1: DoubleDiscountDay = 'Monday'; // Error
6.Omit
Pick 和 Exclude 进行组合, 实现忽略对象某些属性功能
type Omit<T, K extends keyof any> = Pick<T, Exclude<keyof T, K>>;
忽略某些属性,不显示:
interface PetInfo {
name: string;
age: string;
}
type NonVipInfo = Omit<PetInfo, 'age'>;
这个和 Pick 功能相反,当要隐藏的字段较少时,用 Omit 方便,当要显示的信息较少时,用 Pick 方便。
7.ReturnType
需求:小明的宠物平台越做越好,想要对接供应商平台,做到自动补货,清点。供应商给了一个函数 F 用于获取信息,并提示说由于他们升级接口,后续返回的数据格式可能会改变。小明想在升级接口时自动发现代码改动点,同步检查。
ReturnType:提取函数的返回类型,ts 原理如下:
type ReturnType<T extends (...args: any) => any> = T extends (...args: any) => infer R ? R : any;
小明可以这样实现:
import { F } from 'vendor';
type Res = ReturnType<F>;
function myFun(res: Res) {...}
在使用 ReturnType 之前,你可能这样做:
function a(): number {
// ...
}
const res: number = a();
直接编码的坏处就是丢失了类型的依赖关系信息,number 类型是依赖于 a() 函数的,如果 a 的返回类型修改,res 的类型也应该修改,不然就埋下了一个定时炸弹,bug 指不准哪天就出现了。
8.NonNullable – 从T中剔除null和undefined。
type T10 = ReturnType<() => string>; // string
type T11 = ReturnType<(s: string) => void>; // void
type T12 = ReturnType<(<T>() => T)>; // {}
type T13 = ReturnType<(<T extends U, U extends number[]>() => T)>; // number[]
type T14 = ReturnType<typeof f1>; // { a: number, b: string }
type T15 = ReturnType<any>; // any
type T16 = ReturnType<never>; // any
type T17 = ReturnType<string>; // Error
type T18 = ReturnType<Function>; // Error
9.InstanceType – 获取构造函数类型的实例类型。
class C {
x = 0;
y = 0;
}
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