当我们使用 TypeScript 时,我们想利用它提供的类型系统限制代码的方方面面,对象的键值,也不例外。

譬如我们有个对象存储每个年级的人名,类型大概长这样:

type Students = Record<string, string[]>;
 

理所当然地,数据就是长这样:

const students: Students = {
Freshman: ["David", "John"],
sophomore: [],
Junior: ["Lily"],
Senior: ["Tom"],
};
 

限制对象键名为枚举

上面数据类型的问题是,年级是有限的几种可值取,而该对象上可任意添加属性,这样显得数据不够纯粹。

所以我们新增枚举,列出可取的值:

export enum Grade {
Freshman,
sophomore,
Junior,
Senior,
}
 

现在,把对象的键名限制为上面枚举就行了。

- type Students = Record<string, string[]>;
+ type Students = Record<Grade, string[]>;
 

这样我们的数据可写成这样:

const students: Students = {
[Grade.Freshman]: ["David", "John"],
[Grade.sophomore]: [],
[Grade.Junior]: ["Lily"],
[Grade.Senior]: ["Tom"],
// Object literal may only specify known properties, and 'blah' does not exist in type 'Students'.ts(2322)
blah: ["some one"],
};
 

这样,限制住了对象身上键名的范围,可以看到如果添加一个枚举之外的键会报错。

更加语义化的枚举值

但上面的做法还是有不妥之处,因为枚举值默认是从 0 开始的数字,这样,作为键值就不够语义了,这点从访问对象的属性时体现了出来:

修正我们的枚举,用更加语义的文本作为其值:

export enum Grade {
Freshman = "Freshman",
sophomore = "sophomore",
Junior = "Junior",
Senior = "Senior",
}
 

此时再使用该枚举时,得到的就不是无意义的数字了。

如果你愿意,枚举值也可以是中文,

export enum Grade {
Freshman = "大一萌新",
sophomore = "大二学弟",
Junior = "大三学妹",
Senior = "大四老司机",
}
 

使用时也是没任何问题的:

键值可选

上面的类型定义还有个问题,即,它要求使用时对象包含枚举中所有值,比如 sophomore 这个年级中并没有人,可以不写,但会报错。

//  Property 'sophomore' is missing in type '{ Freshman: string[]; Junior: string[]; Senior: string[]; }' but required in type 'Students'.ts(2741)
const students: Students = {
[Grade.Freshman]: ["David", "John"],
// [Grade.sophomore]: [],
[Grade.Junior]: ["Lily"],
[Grade.Senior]: ["Tom"],
};
 

所以,优化类型为可选:

type Students = Partial<Record<Grade, string[]>>;
 

限制对象的键名为数组中的值

假若可选的值不是通过枚举定义,而是来自一个数组,

const grades = ["Freshman", "sophomore", "Junior", "Senior"];
 

这意味着我们需要提取数组中的值形成一个联合类型。

首先利用const assertions 把数组转元组(Tuple)类型,

const grades = <const>["Freshman", "sophomore", "Junior", "Senior"];
 

再利用 typeofLookup Types 得到最终的联合类型:

// 实际为 type Keys = "Freshman" | "sophomore" | "Junior" | "Senior"
type Keys = typeof grades[number];
 

最后数据类型和数据可写成:

type Students = Partial<Record<Keys, string[]>>;

const students: Students = {
Freshman: ["David", "John"],
Junior: ["Lily"],
Senior: ["Tom"],
};
 

须知这种形式下,对象的 key 与原数组中元素其实没有语法层面的关联,即,编辑器的「跳转定义」是不可用的。

尽量还是保持代码之间的关联才能体现出 TypeScript 的作用,所以像这种只有类型约束而无法建立关联的操作是不建议的。

相关资源

The text was updated successfully, but these errors were encountered:

TypeScript 中限制对象键名的取值范围的更多相关文章

  1. JS中JSON对象的定义和取值

    1.JSON(JavaScript Object Notation)一种简单的数据格式,比xml更轻巧.JSON是JavaScript原生格式,这意味着在JavaScript中处理JSON数据不需要任 ...

  2. json对象中的变量存在空格的取值办法

    写一个json对象,但需求需要是带空格的键,定义的话很容易定义,只需要双引号引起来即可,但取值的时候怎么取,直接写 会报错,所以就有了下边的办法 <el-form-item label=&quo ...

  3. (文章也有问题,请自行跳过)react中的状态机每次setState都是重新创建新的对象,如需取值,应该在render中处理。

    demo如下 class Demo4StateLearn extends React.Component { constructor(props) { super(props); this.state ...

  4. MySQL 处理插入过程中的主键唯一键重复值办法

    200 ? "200px" : this.width)!important;} --> 介绍 本篇文章主要介绍在插入数据到表中遇到键重复避免插入重复值的处理方法,主要涉及到I ...

  5. Salesforce中所有常用类型字段的取值与赋值

    Salesforce中所有常用字段类型的定义以及如何用代码进行取值和赋值: Field Type的定义: http://www.salesforce.com/us/developer/docs/api ...

  6. spring中PropertyPlaceholderConfigurer的运用---使用${property-name}取值

    代码如下: 配置文件: jdbc.properties的代码如下: jdbc.driverClassName=org.hsqldb.jdbcDriver jdbc.url=jdbc:hsqldb:hs ...

  7. CDM中遍历域及其约束条件、取值范围、引用它的项目

    Option   ExplicitValidationMode   =   TrueInteractiveMode =   im_BatchDim   mdl   '当前model'获取当前活动mod ...

  8. PyQt(Python+Qt)学习随笔:Mode/View中的枚举类 QItemSelectionModel.SelectionFlag取值及含义

    老猿Python博文目录 专栏:使用PyQt开发图形界面Python应用 老猿Python博客地址 以上取值可以通过或操作进行组合使用. 老猿Python,跟老猿学Python! 老猿Python博文 ...

  9. javascript对象转换,动态属性取值

    $(document).ready(function(){ var exceptionMsg = '${exception.message }'; var exceptionstr = ''; //j ...

随机推荐

  1. JSP配置虚拟路径及虚拟主机

    1.tomact解压后目录 bin:可执行文件(startup.bat   shutdown.bat) conf:配置文件(server.xml) lib:tomcat以来的jar文件 log:日志文 ...

  2. MQ 架构与细节

    MQ 架构与细节 MQ 是什么? MQ:MessageQueue,消息队列的简称,用于进程间通信或同一进程的不同线程间的通信方式. 什么时候该使用MQ? 数据驱动的任务依赖 上游不关心执行结果 上游关 ...

  3. 开源的 Switch 模拟器——GitHub 热点速览 v.21.12

    作者:HelloGitHub-小鱼干 脸滚键盘操作选手小鱼干这里要推荐一个超酷 Switch 模拟器,不能埋没你的游戏天赋.Ryujinx 是一个 C# 写的 Switch 模拟器,1700+ 游戏可 ...

  4. 翻译 - ASP.NET Core 基本知识 - 配置(Configuration)

    翻译自 https://docs.microsoft.com/en-us/aspnet/core/fundamentals/configuration/?view=aspnetcore-5.0 ASP ...

  5. 学《跟我一起写Makefile》笔记发博词

    目录 笔记发博词 参考 笔记发博词 本系列笔记主要记录学了<跟我一起写Makefile>后的一些笔记 由于<跟我一起写Makefile>已经写得很详细了,所以我只是提取其中重要 ...

  6. 自动统计zabbix过去一周监控告警

    # -*- coding:utf-8 -*-import jsonimport requestsimport time,datetimeimport csv,chardetdef getToken(u ...

  7. 无法打开“&#215;&#215;&#215;”,因为无法确认开发者的身份——解决办法

    当打开这些应用程序时,系统提示无法打开" XXX",因为它来自身份不明的开发者.我们可以按照下面的方法解决. 教程 1.打开应用程序,找到你要打开的软件.按住control键,点击 ...

  8. 201871030116-李小龙 实验三 结对项目—《D{0-1}KP 实例数据集算法实验平台》项目报告

    项目 内容 课程班级博客链接 https://edu.cnblogs.com/campus/xbsf/2018CST 这个作业要求链接 https://www.cnblogs.com/nwnu-dai ...

  9. BUAA_2020_OO_UNIT4_REVIEW&ALL_REVIEW

    OO第四单元总结&&学期总结 1. 第四单元作业总结 本单元三次作业都围绕了UML图的建模展开,第十三次作业只有类图,第十四次作业增加了顺序图和状态图,第十五次增加了部分UML规则的判 ...

  10. Go-14-解决 go get golang.org/x/text 拉取失败问题

    现象 在执行go get -v github.com/spf13/cobra/cobra 时,报go get golang.org/x/text 拉取失败问题 解决方法: 在 ${gopath}/sr ...