TypeScript 中如何限制对象键名的取值范围

 更新时间:2021年05月20日 08:50:39   作者:刘哇勇  
TypeScript由微软开发的自由和开源的编程语言,是一种给 JavaScript 添加特性的语言扩展,接下来通过本文给大家介绍TypeScript 中如何限制对象键名的取值范围,感兴趣的朋友跟随小编一起看看吧

当我们使用 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 的作用,所以像这种只有类型约束而无法建立关联的操作是不建议的。

相关资源

const assertions

keyof and Lookup Types

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

以上就是TypeScript 中限制对象键名的取值范围的详细内容,更多关于TypeScript限制对象键名范围的资料请关注脚本之家其它相关文章!

相关文章

  • IE6-IE9中tbody的innerHTML不能赋值的解决方法

    IE6-IE9中tbody的innerHTML不能赋值的解决方法

    这篇文章主要介绍了IE6-IE9中tbody的innerHTML不能赋值的解决方法,需要的朋友可以参考下
    2014-06-06
  • 微信小程序实现简单的购物车功能

    微信小程序实现简单的购物车功能

    这篇文章主要为大家详细介绍了微信小程序实现简单的购物车功能,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2022-07-07
  • js实现0ms延时定时器的几种方式

    js实现0ms延时定时器的几种方式

    本文主要介绍了js实现0ms延时定时器的几种方式,文中通过示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2021-07-07
  • javaScript合并对象的几个常见方式

    javaScript合并对象的几个常见方式

    JavaScirpt中有很多对象合并的方法,今天就做个笔记,记录一下这些方法,下面这篇文章主要介绍了javaScript合并对象的多种方式,文中通过实例代码介绍的非常详细,需要的朋友可以参考下
    2023-05-05
  • 最好用的Bootstrap fileinput.js文件上传组件

    最好用的Bootstrap fileinput.js文件上传组件

    这篇文章主要为大家详细介绍了最好用的Bootstrap fileinput.js文件上传组件的使用方法,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2016-12-12
  • jQuery NProgress.js加载进度插件的简单使用方法

    jQuery NProgress.js加载进度插件的简单使用方法

    NProgress是基于jquery的,且版本要 >1.8 。这篇文章主要介绍了NProgress.js加载进度插件的简单使用方法,需要的朋友可以参考下
    2018-01-01
  • javascript实现数字时钟效果

    javascript实现数字时钟效果

    这篇文章主要为大家详细介绍了javascript实现数字时钟效果,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2021-02-02
  • 除Console.log()外更多的Javascript调试命令

    除Console.log()外更多的Javascript调试命令

    本篇文章给大家介绍了除Console.log()外更多的Javascript调试命令,方便大家更多环境下的JS调试,学习下吧。
    2018-01-01
  • javascript实现点击小图显示大图

    javascript实现点击小图显示大图

    这篇文章主要为大家详细介绍了javascript实现点击小图显示大图,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2020-11-11
  • js判断非127开头的IP地址的实例代码

    js判断非127开头的IP地址的实例代码

    这篇文章主要介绍了js判断非127开头的IP地址,本文通过实例代码给大家介绍的非常详细,具有一定的参考借鉴价值,需要的朋友可以参考下
    2020-01-01

最新评论