在JS中咱们能够经过 for...in
遍历出一个 object{}
的全部 key 而后进行一些逻辑处理,那么在 TS 中是否有相似的功能用于遍历 interface{}
,在 TS2.1 版本就推出了此能力。git
它得出的结果只能赋值给类型,最简单的书写格式:github
{ [ K in P ] : T }
复制代码
下面咱们对其中的 K
、P
、T
各自表示什么,都进行详细的说明。函数
type Coord = {
[K in 'x' | 'y']: number;
};
// 获得
// type Coord = {
// x: number;
// y: number;
// }
复制代码
首选肯定它执行了一个循环(能够理解为相似 for...in 的效果),这里的 P 直接设置为 'x' | 'y'
的一个联合类型,而 K 是一个标识符,它映射为 P 的每个子类型。T 为数据类型,咱们直接固定为 number,也能够是任何其余复杂类型。ui
由于 T 值数据类型能够是任何值,甚至数值 1 也能够,所以咱们把数据类设成 K 自身也行:spa
type Coord = { [K in 'x' | 'y']: K };
// 获得 type Coord = { x: 'x'; y: 'y'; }
复制代码
type Item = {
a: string
b: number
c: boolean
}
// Item 的全部属性的一个 联合类型
type ItemKeys = 'a' | 'b' | 'c';
// 也能够简写为:
// type ItemKeys = keyof Item;
type Copy = { [K in ItemKeys]: Item[K] };
// 获得 type Copy = { a: string, b: number, c: boolean };
复制代码
这里的 Copy 类型与 Item 中的声明彻底同样,能够简写为:code
type Item = { a: string, b: number, c: boolean };
type Copy = { [K in keyof Item]: Item[K] };
// 获得 type Copy = { a: string, b: number, c: boolean };
复制代码
基于此特性再结合 索引访问类型,咱们能够封装出一个复制效果的函数类型:继承
type Copy<P> = { [K in keyof P]: P[K] }
type Item = { a: string, b: number, c: boolean };
type ItemCopy = Copy<Item>;
// 获得 type ItemCopy = { a: string, b: number, c: boolean };
复制代码
基于此特性封装一个快速生成接口类型的函数类型:索引
type Create<P extends keyof any, T> = { [K in P]: T };
type Coord = Create<'x' | 'y', number>;
// 获得 type Coord = { x: number, y: number };
复制代码
若是你很眼熟,则说明你见过或用过官方预置的高级类型 Record<K extends keyof any, T>
,是的,他们如出一辙。接口
这里的 extends
条件类型用于继承的做用,此时咱们传入的 联合类型。因 P
必须可分配给 string
类型的缘由,咱们须要进行一些限制,确保接收到的 P 是有效的值。ip
而 keyof 的一个特性: keyof T
的类型会被认为是 string
、number
、symbol
的子类型。(关于 keyof 的更多特性以后将讲解)基于 keyof any
的检测,所以下面的使用都会报错:
type Val = Create<true, boolean>;
// Error: Type 'true' does not satisfy the constraint 'string | number | symbol'.
type Val2 = Create<() => void>;
// Error: Type '() => void' does not satisfy the constraint 'string | number | symbol'
复制代码
还可使用 readonly
或 ?
对属性进行设置:
type Coord = {
readonly [K in 'x' | 'y']: number
};
// 获得
// type Coord = {
// readonly x: number;
// readonly y: number;
// };
复制代码
两个装饰符也可组合使用:
type Coord = {
readonly [K in 'x' | 'y']?: number;
};
// 获得
// type Coord = {
// readonly x?: number;
// readonly y?: number;
// };
复制代码
但这里面也有局限性,没法去除属性上已经存在的 装饰符:
type CoordOptional = {
x?: number;
readonly y: number;
};
type Coord = {
[K in keyof CoordOptional]: number;
};
// 获得
// type Coord = {
// x?: number;
// readonly y: number;
// };
复制代码
由于这个缘由,社区又在 TS2.8 又对其进行了完善,能够在上面的装饰符添加 -
或 +
符号:
type CoordOptional = {
x?: number;
readonly y: number;
};
type Coord = {
-readonly [K in keyof CoordOptional] -?: number;
};
// 获得
// type Coord = {
// x: number;
// y: number;
// };
复制代码