当我们使用 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. Java系列教程-MyBatis 3.5.5 教程目录

    MyBatis 3.5.5 初级教程目录 可参考MyBatis的官方文档也比较清楚 https://mybatis.org/mybatis-3/zh/getting-started.html 代码 目 ...

  2. JetBrains Projector 体验

    先来一张最终效果图: JetBrains Projector 是 JetBrains 的"远程开发"解决方案,基于 Client + Server 架构,对标的是微软 VSCode ...

  3. 微信小程序实现搜索关键词高亮

    目录 1,前言 2,思路 3,代码逻辑 1,前言 项目中碰到一个需求,搜索数据并且关键词要高亮显示,接到需求,马上开干.先上效果图.源码已经做成了小程序代码片段,放入了GitHub了,文章底部有源码链 ...

  4. css盒模型以及如何计算盒子的宽度

    css盒模型以及如何计算盒子的宽度 盒模型 每个存在于可访问性树中的元素都会被浏览器绘制成一个盒子[1]. 每个盒子都可以看成由4部分组成,它们分别是 - 元素外边距(margin).元素边框(bor ...

  5. java面试-强引用、软引用、弱引用和幻象引用有什么区别

    在Java语言中,除了基本数据类型外,其他的都是指向各类对象的对象引用:Java中根据其生命周期的长短,将引用分为4类. 不同的引用类型,主要体现的是对象不同的可达性状态和对垃圾收集的影响. 1 .强 ...

  6. OO第四单元——基于UML的UML解析器总结&OO课程总结

    OO第四单元--基于UML的UML解析器总结&OO课程总结 前言:一学期愉快(痛苦)的OO课程学习结束了,OO几个单元作业都各有特色,实验也各有特色,仔细回味起来,不再是单纯的敲代码(但自己还 ...

  7. 基于gitlab的项目管理流程

    框架 背景 个人是不太愿意使用用户体验差的软件来做项目管理,行业内,要找到这么一款软件,又要符合自己的需求,着实不容易.要免费,易用性要好,要安全,要有数据统计.而程序员的世界,SVN 之后,可能没有 ...

  8. html5 video/audio 标签

    一般来说推荐使用,第三方的媒体播放库[例如 videojs 等],这些库的ui界面,js控制都已写好,功能也扩展的比较丰富 ,直接参考文档使用更加的高效! 这里还是 记录一下 html 原生 vide ...

  9. JAVAEE_Servlet_12_获取前端页面请求方式 HttpServletRequest HttpServletResponse

    获取前端页面请求方式 * 前端页面发送的请求方式应该是后端服务器需要的请求方式保持一致,若不一致应该提示错误信息. * 获取到前端的请求方式之后通过if语句进行判断, if("GET&quo ...

  10. 判断请求是否属于Ajax请求

    我们有时候需要根据请求类型来判断返回视图名称还是JSON数据,这里记录一个判断Ajax的工具类方便日后好找 通过传入Request对象获取头信息,根据头信息判断是否属于Ajax请求 public cl ...