共计 1878 个字符,预计需要花费 5 分钟才能阅读完成。
最近使用 TypeScript 写了一个项目, 过程中不断感受到 TypeScript 的魅力, 现在来分享几个业务中关于泛型的场景
1. 深度 Partial
TS 内置了一个 Partial
类型, 用于把一个类型的成员属性设置为成可选模式, 例如
type Person = {
name: string;
age: number;
}
Person
类型中有两个成员属性, 如果我们要把这个类型赋予变量 tom
, 那tom
必须拥有 name
和age
两个属性
let tom:Person = {
name: 'tom',
age: 20
};
现在我们要让 Person
的两个属性都变为可选, 可以使用 Partial
类型进行转换
type PartialPerson = Partial<Person>;
let partialPerson: PartialPerson = {name: 'tom'};
这时 PartialPerson
的name
和 age
属性都已经变为可选的了, 但是如果我们在 Person
中再加一点东西
type Person = {
name: string;
age: number;
contact: {
email: string;
phone: number;
wechat: string;
}
}
现在我们加入了一个 contact
属性值是一个对象, 如果我们想把 contact
里面的属性也变为可选 Partial
就不灵了
可以看到 Partial
是把 contact
变成了可选而不是里面的属性, 插个题外话通常的做法是为 contact
另外创建一个类型, 如果是这样的话 Partial
就可以用了, 但是我们不使用这种方法, 我们先来看看 TS 是怎么定义 Partial
的
/**
* Make all properties in T optional
*/
type Partial<T> = {[P in keyof T]?: T[P];
};
很容易理解关键点是在 ?:
上, 现在我们改造一下
type DeepPartial<T> = {[P in keyof T]?: T[P] extends Object ? DeepPartial<T[P]> : T[P];
}
可以看到改造的 DeepPartial
跟Partial
差别在把直接赋值 T[P]
换成了 T[P] extends Object ? DeepPartial<T[P]> : T[P]
, 即判断 T 的属性 P 的类型是否是Object
然后进行再次 DeepPartial
或者返回 T[P]
的类型
这时编译器就不会再提示错误了
2. 更智能的 array_column
函数
在 PHP 中有一个 array_column
函数, 用于在数组中提取一列的内容, 用 JavaScript 表现就是
function array_column(arr, key) {return arr.map(item => item[key])
}
假如现在有一个 persons
数组
type Person = {
name: string;
age: number;
}
let persons: Person[] = [];
我们需要提取数组中的 name
属性, 可以很方便的使用 Array.map
方法提取, 但是如果又有别的数组需要提取, 我们可以实现一个更优雅的 array_column
函数
function array_column<T, K extends keyof T>(input: T[], key: K) {return input.map(item => item[key])
}
现在我们使用这个函数提取 persons
数组
可以看到当我们输入 persons
时, 编辑器已经推断出了 key
的类型, 再来一个 animals
数组
3. Proxy
在刚开始学习 TS 的时候看官方文档有一个 Proxy 的例子, 只给出了类型声明但却没有给出实现, 当时花了不少时间琢磨, 现在来实现它
class Proxy<T>{constructor(private data: T) { }
get<K extends keyof T>(key: K) {return this.data[key]
}
set<K extends keyof T, V extends T[K]>(key: K, value: V) {this.data[key] = value;
}
}
可以看到 Proxy 类提供了 getter
方法 get
和setter
方法 set
, 现在我们基于上面的Person
类型创建一个 Proxy 实例
let person: Person = {
name: 'tom',
age: 18
};
let proxy = new Proxy(person);
现在我们来看看调用 get
方法
可以看到编辑器也推断出了参数 key
的类型, 再来看看 set
方法
和 get
方法一样, 编辑器也推断出了参数 key
的类型, 同时也推断出了参数 value
的类型为string