typescript 高级技巧

高级技巧

keyof

keyofObject.keys 略有相似,只不过 keyofinterface 的键

1
2
3
4
5
6
7
8
interface Point {
x: number;
y: number;
}

type keys = keyof Point;
// type keys = "x" | "y"
// 表示 keys 的类型鉴于 x 和 y 的联合类型

使用 typescript 实现一个 get 函数来获取它的属性值

1
2
3
4
5
6
7
8
const data = {
a: 3,
hello: 'world'
}

function get(o: object, name: string) {
return o[name]
}

但是它无法确认返回值类型, 也无法对 key 进行约束

这时候可以使用 keyof

1
2
3
function get<T extends object, K extends keyof T>(o: T, name: K): T[K] {
return o[name]
}

给定一个对象类型 Xkeyof X 的类型求值过程如下:

  1. 如果 X 包含字符串索引签名,那么 keyof X 的值为 stringnumber 和类符号属性名的字面量类型组成的联合类型,否则下一步
  2. 如果 X 包含数值索引签名,那么 keyof X 的值为 number 和类字符串与类符号属性名的字面量类型组成的联合类型,否则下一步
  3. keyof X 的值为类字符串、类数值和类符号属性名的字面量类型组成的联合类型

其中,

  • 对象的类字符串(string-like)属性名包括标识符、字符串字面量和字符串字面量类型的计算属性名
  • 对象的类数值(number-like)属性名包括数值字面量和数值字面量类型的计算属性名
  • 对象的类符号(symbol-like)属性名包括符号类型的计算属性名
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
const c = "c";
const d = 10;
const e = Symbol();

const enum E1 { A, B, C }
const enum E2 { A = "A", B = "B", C = "C" }

type Foo = {
a: string; // string-like,标识符
5: string; // number-like, 数值字面量
[c]: string; // string-like, 字符串字面量类型的计算属性
[d]: string; // number-like, 数值字面量类型的计算属性
[e]: string; // symbol-like, 符号类型的计算属性
[E1.A]: string; // number-like, 数值枚举类型的计算属性
[E2.A]: string; // string-like, 字符串枚举类型的计算属性
}

type K1 = keyof Foo; // "a" | 5 | "c" | 10 | typeof e | E1.A | E2.A;
type K2 = Extract<keyof Foo, string>; // "a" | "c" | E2.A
type K3 = Extract<keyof Foo, number>; // 5 | 10 | E1.A
type K4 = Extract<keyof Foo, symbol>; // typeof e


type K5 = keyof { [x: string]: Person }; // string | number

typeof

在 TypeScript 中,typeof 操作符可以用来获取一个变量声明或对象的类型。

1
2
3
4
5
6
7
8
9
10
11
12
13
interface Person {
name: string;
age: number;
}

const sem: Person = { name: 'semlinker', age: 18 };
type Sem= typeof sem; // -> Person

function toArray(x: number): Array<number> {
return [x];
}

type Func = typeof toArray; // -> (x: number) => number[]

参考资料

https://shanyue.tech/post/ts-tips.html