浅谈TypeScript 索引签名的理解

目录
  • 1.什么是索引签名
  • 2. 索引签名语法
  • 3. 索引签名的注意事项
    • 3.1不存在的属性
    • 3.2 string 和 number 键
  • 4.索引签名与 Record<Keys, Type>对比

我们用两个对象来描述两个码农的工资:

const salary1 = {
  baseSalary: 100_000,
  yearlyBonus: 20_000
};

const salary2 = {
  contractSalary: 110_000
};

然后写一个获取总工资的函数

function totalSalary(salaryObject: ???) {
  let total = 0;
  for (const name in salaryObject) {
    total += salaryObject[name];
  }
  return total;
}
totalSalary(salary1); // => 120_000
totalSalary(salary2); // => 110_000

如果是你的,要如何声明totalSalary()函数的salaryObject参数,以接受具有字符串键和数字值的对象?

答案是使用一个索引签名!

接着,我们来看看什么是 TypeScript 索引签名以及何时需要它们。

1.什么是索引签名

索引签名的思想是在只知道键和值类型的情况下对结构未知的对象进行类型划分。

它完全符合salary参数的情况,因为函数应该接受不同结构的salary对象,唯一的要求是属性值为数字。

我们用索引签名来声明salaryObject参数

function totalSalary(salaryObject: { [key: string]: number }) {
  let total = 0;
  for (const name in salaryObject) {
    total += salaryObject[name];
  }
  return total;
}

totalSalary(salary1); // => 120_000
totalSalary(salary2); // => 110_000

{[key: string]: number} 是索引签名,它告诉TypeScript salaryObject 必须是一个以string 类型为键,以 number 类型为值的对象。

2. 索引签名语法

索引签名的语法相当简单,看起来与属性的语法相似,但有一点不同。我们只需在方括号内写上键的类型,而不是属性名称:{ [key: KeyType]: ValueType }。

下面是一些索引签名的例子。

string 类型是键和值。

interface StringByString {
  [key: string]: string;
}

const heroesInBooks: StringByString = {
  'Gunslinger': '前端小智',
  'Jack Torrance': '王大志'
};

string 类型是键,值可以是 stringnumberboolean

interface Options {
  [key: string]: string | number | boolean;
  timeout: number;
}

const options: Options = {
  timeout: 1000,
  timeoutMessage: 'The request timed out!',
  isFileUpload: false
};

签名的键只能是一个 string`、numbersymbol`。其他类型是不允许的。

3. 索引签名的注意事项

TypeScript中的索引签名有一些注意事项,需要注意。

3.1不存在的属性

如果试图访问一个索引签名为 { [key: string]: string } 的对象的一个不存在的属性,会发生什么?

正如预期的那样,TypeScript 将值的类型推断为 string。但是检查运行时值,它是undefined:

根据 TypeScript 提示, value变量是一个 string 类型,但是它的运行时值是 undefined

索引签名只是将一个键类型映射到一个值类型,仅此而已。如果没有使这种映射正确,值类型可能会偏离实际的运行时数据类型。

为了使输入更准确,将索引值标记为 string undefined。这样,TypeScript就会意识到你访问的属性可能不存在

3.2 string 和 number 键

假设有一个数字名称的字典:

interface NumbersNames {
  [key: string]: string
}

const names: NumbersNames = {
  '1': 'one',
  '2': 'two',
  '3': 'three',
  // ...
};

不会,正常工作。

当在属性访问器中作为键使用时,JavaScript隐式地将数字强制为字符串(names[1]names['1']相同)。TypeScript也会执行这个强制。

你可以认为 [key: string] 与 [key: string | number] 相同。

4.索引签名与 Record<Keys, Type>对比

TypeScript有一个实用类型 Record<Keys, Type>,类似于索引签名。

const object1: Record<string, string> = { prop: 'Value' }; // OK
const object2: { [key: string]: string } = { prop: 'Value' }; // OK

那问题来了...什么时候使用 Record<Keys, Type>,什么时候使用索引签名?乍一看,它们看起来很相似

我们知道,索引签名只接受 stringnumber symbol 作为键类型。如果你试图在索引签名中使用,例如,字符串字面类型的联合作为键,这是一个错误。

索引签名在键方面是通用的。

但是我们可以使用字符串字面值的联合来描述 Record<keys, Type>中的键

type Salary = Record<'yearlySalary'|'yearlyBonus', number>

const salary1: Salary = {
  'yearlySalary': 120_000,
  'yearlyBonus': 10_000
}; // OK

Record<Keys, Type> 是为了具体到键的问题。

建议使用索引签名来注释通用对象,例如,键是字符串类型。但是,当你事先知道键的时候,使用Record<Keys, Type>来注释特定的对象,例如字符串字面量' prop1' | 'prop2'被用于键值。

 总结:

如果你不知道你要处理的对象结构,但你知道可能的键和值类型,那么索引签名就是你需要的。

索引签名由方括号中的索引名称及其类型组成,后面是冒号和值类型: { [indexName: KeyType]: ValueType }, KeyType 可以是一个 stringnumber symbol,而ValueType 可以是任何类型。

到此这篇关于浅谈TypeScript 索引签名的理解的文章就介绍到这了,更多相关TypeScript 索引签名内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • Vue3+TypeScript实现递归菜单组件的完整实例

    目录 前言 需求 实现 首次渲染 点击菜单项 样式区分 默认高亮 数据源变动引发的 bug 完整代码 App.vue 总结 前言 小伙伴们好久不见,最近刚入职新公司,需求排的很满,平常是实在没时间写文章了,更新频率会变得比较慢. 周末在家闲着无聊,突然小弟过来紧急求助,说是面试腾讯的时候,对方给了个 Vue 的递归菜单要求实现,回来找我复盘. 正好这周是小周,没想着出去玩,就在家写写代码吧,我看了一下需求,确实是比较复杂,需要利用好递归组件,正好趁着这 个机会总结一篇 Vue3 + TS 实现递

  • TypeScript中条件类型精读与实践记录

    目录 在泛型类型中使用条件类型 工具类型 逃离舱 在箭头函数中使用条件类型 结合类型推导使用条件类型 使用条件类型来判断两个类型完全相等 总结 在大多数程序中,我们必须根据输入做出决策.TypeScript 也不例外,使用条件类型可以描述输入类型与输出类型之间的关系. 用于条件判断时的 extends 当 extends 用于表示条件判断时,可以总结出以下规律 若位于 extends 两侧的类型相同,则 extends 在语义上可理解为 ===,可以参考如下例子: type result1 =

  • TypeScript枚举的基础知识及实例

    目录 前言 TypeScript 中的枚举是什么 在 TypeScript 中使用枚举需要注意什么 常见枚举的类型 枚举反向映射 计算枚举 总结 前言 枚举是受 TypeScript 支持的数据类型.枚举允许您定义一组命名常量.使用它们可以更轻松地记录意图或创建一组不同的案例.枚举大多数用于面向对象的编程语言(如 Java 和 C#)中,现在也可以 TypeScript 中使用.它们是 TypeScript 的少数功能之一,它不是 JavaScript 的类型级扩展.接下来我将要演示 TypeS

  • typescript+react实现移动端和PC端简单拖拽效果

    本文实例为大家分享了typescript+react实现移动端和PC端简单拖拽效果的具体代码,供大家参考,具体内容如下 一.移动端 1.tsx代码 import { Component } from "react"; import './Tab.less' interface Props { } interface user { id: string, text: string } interface content { id: string, text: string } inter

  • Vue3结合TypeScript项目开发实战记录

    目录 概述 1.compositon Api 1.ref 和 reactive的区别? 2.周期函数 3.store使用 4.router的使用 2.关注点分离 3.TypeScript支持 总结 概述 Vue3出来已经有一段时间了,在团队中,也进行了大量的业务实践,也有了一些自己的思考. 总的来说,Vue3无论是在底层的原理上,还是在业务的实际开发中,都有了长足的进步. 使用 proxy 代替之前的 Object.defineProperty 的API,性能更加优异,也解决了之前vue在处理对

  • React项目中应用TypeScript的实现

    目录 一.前言 二.使用方式 无状态组件 有状态组件 受控组件 三.总结 一.前言 单独的使用typescript 并不会导致学习成本很高,但是绝大部分前端开发者的项目都是依赖于框架的 例如和vue.react 这些框架结合使用的时候,会有一定的门槛 使用 TypeScript 编写 react 代码,除了需要 typescript 这个库之外,还需要安装@types/react.@types/react-dom npm i @types/react -s npm i @types/react-

  • Vue3 + TypeScript 开发总结

    目录 Vue3 + TypeScript 学习 一, 环境配置 1.1 安装最新 Vue 脚手架 1.2 创建Vue3 项目 二, 进击Vue3 2. 1 Vue 2 局限性 2.2 Vue 3 如何解决Vue 2 局限 三,Vue3 Composition Ap i 3.1 关于 Composition Api 3.2 什么时候使用Composition Api 四,Composition Api 必备基础 4.2 ref 创建响应式变量 4.3 生命周期 4.4 watch 4.5 comp

  • webpack搭建脚手架打包TypeScript代码

    创建文件夹 目录结构: dabaots 初始化 npm init -y生成package.json文件 目录结构: dabaots dabaots / package.json 然后在开发环境中安装以下几个工具 npm i -D webpack··························(打包代码的核心工具 webpack-cli·····················(webpack的命令行工具) typescript ·······················(写ts所需的核心

  • vue中使用TypeScript的方法

    引言 近几年前端对 TypeScript的呼声越来越高,Typescript也成为了前端必备的技能.TypeScript 是 JS类型的超集,并支持了泛型.类型.命名空间.枚举等特性,弥补了 JS 在大型应用开发中的不足. 在单独学习 TypeScript时,你会感觉很多概念还是比较好理解的,但是和一些框架结合使用的话坑还是比较多的,例如使用 React.Vue 这些框架的时候与 TypeScript 的结合会成为一大障碍,需要去查看框架提供的.d.ts的声明文件中一些复杂类型的定义.组件的书写

  • 浅谈TypeScript 索引签名的理解

    目录 1.什么是索引签名 2. 索引签名语法 3. 索引签名的注意事项 3.1不存在的属性 3.2 string 和 number 键 4.索引签名与 Record<Keys, Type>对比 我们用两个对象来描述两个码农的工资: const salary1 = { baseSalary: 100_000, yearlyBonus: 20_000 }; const salary2 = { contractSalary: 110_000 }; 然后写一个获取总工资的函数 function tot

  • 浅谈typescript中keyof与typeof操作符用法

    目录 一.keyof 简介 二.keyof 的作用 三.keyof 与对象的数值属性 四.keyof 与 typeof 操作符 一.keyof 简介 TypeScript 允许我们遍历某种类型的属性,并通过 keyof 操作符提取其属性的名称.keyof 操作符是在 TypeScript 2.1 版本引入的,该操作符可以用于获取某种类型的所有键,其返回类型是联合类型.下面我们来看个例子: interface Person {   name: string;   age: number;   lo

  • 浅谈C#索引器

    目录 一.概要 二.应用场景 一.概要 索引器使你可从语法上方便地创建类.结构或接口,以便客户端应用程序可以像访问数组一样访问它们.编译器将生成一个 Item 属性(或者如果存在 IndexerNameAttribute,也可以生成一个命名属性)和适当的访问器方法.在主要目标是封装内部集合或数组的类型中,常常要实现索引器.例如,假设有一个类 TempRecord,它表示 24 小时的周期内在 10 个不同时间点所记录的温度(单位为华氏度).此类包含一个 float[] 类型的数组 temps,用

  • 浅谈对yield的初步理解

    如下所示: def go(): while True: data = 1 r = yield data # data是返回值,r是接收值 print("data", data) print("A1", r) data += 1 r = yield data print("data",data) r += r print("A2", r) data += 1 r = yield data print("data&quo

  • 浅谈对于DAO设计模式的理解

    为了降低耦合性,提出了DAO封装数据库操作的设计模式. 它可以实现业务逻辑与数据库访问相分离.相对来说,数据库是比较稳定的,其中DAO组件依赖于数据库系统,提供数据库访问的接口. 一般的DAO的封装由以下另个原则:  · 一个表对应一个表,相应地封装一个DAO类.  · 对于DAO接口,必须由具体的类型定义.这样可以避免被错误地调用. 在DAO模式中,将对数据的持久化抽取到DAO层,暴露出Service层让程序员使用,这样,一方面避免了业务代码中混杂JDBC调用语句,使得业务落实实现更加清晰.

  • 浅谈关于C++memory_order的理解

    看了c++并发编程实战的内存模型部分后,一直对memory_order不太懂,今天在知乎发现了百度的brpc,恰好有关于原子操作的文档,感觉解释的很好.为了加深理解,再次总结一遍. 在多核编程中,我们使用锁来避免多个线程修改同一个数据时产生的竞争条件.但是,锁会消耗系统资源,当锁成为性能瓶颈的时候,就需要使用另一种方法--原子指令.c++11中引入了原子类型atomic. 原子指令 (x均为std::atomic) 作用x.load()返回x的值.x.store(n)把x设为n,什么都不返回.x

  • 浅谈数据库索引的作用及原理

    数据库索引是为了增加查询速度而对表字段附加的一种标识.很多人机械的理解索引的概念,认为增加索引只有好处没有坏处.其实远不是那样的,这里将其介绍尽量详细些. 首先明白为什么索引会增加速度,DB在执行一条Sql语句的时候,默认的方式是根据搜索条件进行全表扫描,遇到匹配条件的就加入搜索结果集合.如果我们对某一字段增加索引,查询时就会先去索引列表中一次定位到特定值的行数,大大减少遍历匹配的行数,所以能明显增加查询的速度.那么在任何时候都应该加索引么?这里有几个反例:1.如果每次都需要取到所有表记录,无论

  • 浅谈对c# 面向对象的理解

    一.了解面向对象 1.概念基本理解:1).一个个体可以看做是一个对象,例如:人这个个体: 2).有共同属性的一类作为一个个体,例如:学生.白领.农民工: 3).结构体是用户自定义的数据类型,可以定义不同数据类型的变量,结构体也是面向对象的核心: 2.基本特性: 1)封装:是隐藏信息的特性,具有"封装"意识,是掌握面向对象分析与设计技巧的关键. 最简单的理解:创建一个对象的整体,使对象的属性可以具有赋值.取值的功能,也就是对象中的变量可以赋值.取值.,是一种认为的抽象出来的对象的概念.

  • 浅谈Java slf4j日志简单理解

    一.理解 slf4j(Simple Logging Facade for Java),表示为java提供的简单日志门面,更底层一点说就是接口.通过将程序中的信息导入到日志系统并记录,实现程序和日志系统的解耦 日志门面接口本身通常并没有实际的日志输出能力,它底层还是需要去调用具体的日志框架API的,也就是实际上它需要跟具体的日志框架结合使用.由于具体日志框架比较多,而且互相也大都不兼容,日志门面接口要想实现与任意日志框架结合可能需要对应的桥接器,就好像JDBC与各种不同的数据库之间的结合需要对应的

  • 浅谈MySQL索引优化分析

    为什么你写的sql查询慢?为什么你建的索引常失效?通过本章内容,你将学会MySQL性能下降的原因,索引的简介,索引创建的原则,explain命令的使用,以及explain输出字段的意义.助你了解索引,分析索引,使用索引,从而写出更高性能的sql语句.还在等啥子?撸起袖子就是干! 案例分析 我们先简单了解一下非关系型数据库和关系型数据库的区别. MongoDB是NoSQL中的一种.NoSQL的全称是Not only SQL,非关系型数据库.它的特点是性能高,扩张性强,模式灵活,在高并发场景表现得尤

随机推荐