iosJohnson 2019-11-05
最近使用TypeScript写了一个项目,过程中不断感受到TypeScript的魅力,现在来分享几个业务中关于泛型的场景
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]的类型

这时编译器就不会再提示错误了
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数组

在刚开始学习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
运算符用于执行程序代码运算,会针对一个以上操作数项目来进行运算。以上实例中 7、5 和 12 是操作数。关系运算符用于计算结果是否为 true 或者 false。逻辑运算符用于测定变量或值之间的逻辑。