1.从in说起
我们知道,in可以用来遍历联合类型。
关于in等ts的相关类型运算,可以参考作者的这篇文章 5分种学会:常见的ts类型运算符
接下来请看下面两张图:
我们可以通过类型映射(即第二张图),实现从类型A得到类型B,达到和图1同样的效果。
keyof就是得到A的键名,组成联合类型,in遍历这些键名,prop这个词可以改叫别的,只是为了遍历。
如果我们不想让x和y变化,希望和A一样呢?
请见下图。
和之前不同的是,我们把string改为A[prop],从左面拿到prop,即可在右面,从A中取到x和y。
好,现在我们可以实现,把A中,每个属性的类型,统一改成另外的类型,成为类型B。
也可以实现不变化,让B中对应属性的类型,保持不变。
那么我们延伸一下,类型可以通过上面的方式实现,属性呢?
如果A中的属性发生了变化,其实也可以理解成,初始的,不一定是A类型了。可能是A1类型/C类型/DEF类型。
我们想把不同的类型,里面属性的类型,都改为number,如何实现呢?
增强复用性,大家可能想到了泛型,那么我们就通过泛型,来简单实现一下这个需求:常用映射+泛型。
2.修饰符
readonly:只读。
?:可选。
我们可以在修饰符前面,加上+或者-,来添加或者移除修饰符。
其中,加号可以省略。下面的A类型和B类型相同。
3.as实现:键名重新映射
如果我们想保持,对应属性的类型不变,改动一下之前的键名,重新映射,可以使用as实现。
4.类型工具的实现
拥有了类型映射这一武器,可以实现一些类型工具。
下面我们实现一下Pick,Readonly,Omit。
Pick
在说Pick之前,我们聊一点前置知识。
extends在ts中,常常会和泛型一起使用,去做类型约束。extends的前面是后面的子类型。
类型约束有什么意义呢?看完下面这段代码就懂了。
第一个函数和第二个函数,看起来作用一样。
区别在于,两个函数的key参数的类型有一点点区别。
这个区别,会在n和m中体现。请看下面两张图的对比。
为什么会有这样的区别呢?
这是因为,一旦加上了K extends keyof T,TypeScript就会尝试寻找,能够满足条件的,最小集合。
ok,接下来实现一下Pick。
Pick,指从类型T中选择(pick)出属性K,构造成一个新的类型。
Readonly
Readonly会接收一个泛型参数,并返回一个完全一样的类型,只是所有属性都会被readonly所修饰。
修饰的话,直接前面加readonly就好。
取所有属性的话,由于只接受一个泛函参数,这里和Pick是有区别的。
Pick接收两个参数,原始类型,要取到的属性k。Readonly只有一个参数,即原始类型。
这里遍历的话,直接keyof,泛型参数只有一个,可以不去extends。
Omit
Omit会创建一个,省略K中字段的T。
先保证K在T中,所以第一行K extends keyof T。
as类型断言。
key extends K ? never : key
这里的意思是通过extends判断,如果key在K中,取never类型,否则就正常取。
never类型的键值,会被忽略,所以达到了省略K的目的,筛选出了不是K的。