用最简单的话讲解Utility Types-Record

466 阅读3分钟

小知识,大挑战!本文正在参与“程序员必备小知识”创作活动。

背景

大家好,我是梅利奥猪猪。上次说了Readonly,其实大家不难发现,源码的实现只要看了都非常容易理解,不要脸的猪猪,讲解方式的本质就是翻译官方文档!所以这次我们换一种方式讲解,自己尝试实现,然后在看源码分析(其实一样是水文啦哈哈),那我们废话不多说,直接开始今天的主角-Record

正文

官方例子

先来看下官方的例子,以及说明(要知道它干嘛用的才能去实现)

Constructs an object type whose property keys are Keys and whose property values are Type. This utility can be used to map the properties of a type to another type.

interface CatInfo {
  age: number;
  breed: string;
}
 
type CatName = "miffy" | "boris" | "mordred";
 
const cats: Record<CatName, CatInfo> = {
  miffy: { age: 10, breed: "Persian" },
  boris: { age: 5, breed: "Maine Coon" },
  mordred: { age: 16, breed: "British Shorthair" },
};
 
cats.boris;

从官方例子中能看到,我们变量cats,是个对象,它的key值就是我们之前定义的type CatName,XDM如果尝试删掉其中一个key就会报错, catName必须都要包含(所以我们实现也需要这样),然后value就是我们定义的接口CatInfo,即每只猫的猫属性都是CatInfo,知道这些信息我们就可以尝试实现了

尝试实现

我们先把最简单的架子搭好

type MyRecord<K, T> = {
    
}

为什么泛型会写两个,很简单,我们使用的时候就是Record<xxx,xxx>(这就是现在流行的废话文学了吧),起名k和t,是key和type的意思,接下来,我们可以想下,一般我们对象的key的值,一般是不是就是字符串,数字,还有个大家可能接触比较少的symbol,所以我们的架子又可以进化成如下代码

type MyRecord<K extends string | number | symbol, T> = {
    
}

联合类型代表的是或者的意思,翻译下就是,可以是string,可以是number,也可以是symbol任意一个类型,还记得前面我们说的,XDM如果尝试删掉其中一个key就会报错, catName必须都要包含(所以我们实现也需要这样)所以接下来我们就要实现这个,遍历开始!

type MyRecord<K extends string | number | symbol, T> = {
    [P in K]: T
}

上面的代码在遍历后,我直接就实现了,因为T就是我们最终Value的类型,所以我们遍历所有key之后,他们的value类型就是我们的T,实现结束,最后我们在来看下源码实现和我们有什么区别吧

源码讲解

上源码看下

/**
 * Construct a type with a set of properties K of type T
 */
type Record<K extends keyof any, T> = {
    [P in K]: T;
};

看上去几乎一毛一样,唯一的区别就是keyof any,这应该是我们的知识盲区了,我们赶快写个ts看下type testKey = keyof any,当我们把鼠标移入testKey的时候就能看到

testKey.png

这不就是我们前面写的string | number | symbol嘛!好的大功告成,XDM学会了嘛,欢迎和小白的我一起讨论学习!今天的水文就到这!

参考