# Previously
JavaScript
是一种动态语言。有时在静态类型系统中捕获某些操作的语义可能会很棘手。
function prop(obj, key) {
return obj && obj[key] ? obj[key] : null; // lodash.get(prop, key)
}
1
2
3
2
3
该函数接收 obj
和 key
两个参数,并返回对应属性的值。对象上的不同属性,可以具有完全不同的类型,我们甚至不知道 obj
对象长什么样。
function prop(obj, key: string) {
return (obj as any)[key];
}
1
2
3
2
3
# 定义 Typescript keyof 关键字
keyof
keyof
也称为输入索引类型查询, 与之相对应的是索引访问类型, 也称为查找类型, 用来取得一个对象接口(某种类型)的所有 key
值, 返回一个联合类型。
# 如何解决上述问题
type Todo = {
id: number;
text: string;
done: boolean;
}
const todo: Todo = {
id: 1,
text: "Learn TypeScript keyof",
done: false
}
// extends 关键字约束该类型必须是 object 类型的子类型
function prop<T extends object, K extends keyof T>(obj: T, key: K) {
return obj[key];
}
// number
const id = prop(todo, "id");
// string
const text = prop(todo, "text");
// boolean
const done = prop(todo, "done");
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
# 使用
interface Profile {
name: string;
age: number;
}
// 'name' | 'age'
type Keys = keyof Profile;
// 'string' | 'number'
type TypeKeys = keyof { [K: string]: Profile};
1
2
3
4
5
6
7
8
9
10
2
3
4
5
6
7
8
9
10
# 访问值
可通过 T[K] 索引访问。
interface Profile {
name: string,
readonly age: number,
}
// string
type Name = Profile['name']
// string | number
type NameAge = Profile['name' | 'age']
// 如果[]中的key有不存在T中的,则是any;
// 因为ts也不知道该key最终是什么类型,所以是any;
// 且也会报错
// any
type GetValueFromUnknownKey = Profile['name' | 'unknownKey']
// string | number
type ProfileValue = Profile[keyof Profile]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
# ⚠️ 注意
对于 任何类型T, keyof T的结果为该类型上所有 公有(public)属性key 的联合。
interface Profile {
name: string,
readonly age: number,
}
// ProfileKeys 的类型实则是 name | age
type ProfileKeys = keyof Profile;
class PersonProfile {
private name: string;
protected home: string;
public readonly age: number;
}
// PersonProfileKeys 实则被约束为 age
// 而 name 和 home 不是公有属性,所以不能被 keyof 获取到
type PersonProfileKeys = keyof PersonProfile;
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
# 快来耍耍啊
# 🌰🌰
// template
1
# 游乐场
# 参考答案
// answer
1