Typescript - 索引签名

目录

  • 1,什么是索引签名
    • 1,js 中使用对象的属性
    • 2,ts 中的索引签名
    • 3,扩展索引签名定义的类型
  • 2,与 Record 对比
  • 3,遇到的问题
    • 1,索引 key 的类型问题,`keyof`
    • 2,索引 key 的类型问题2:受具体定义的影响

1,什么是索引签名

1,js 中使用对象的属性

在 js 中,访问对象的 key

let user = {name: "下雪天的夏风",19: "19value",
};console.log(user.name);
console.log(user[19]);
user.age = 18

如果key对象,会默认执行它的 toString() 方法。

let user = {name: "下雪天的夏风",
};
const obj = {toString() {console.log("be string");return "_obj";},
};user[obj] = "关注一波";
console.log(user);
// be string
// { name: '下雪天的夏风', _obj: '关注一波' }

其他的类型,来看下结果

let user = {};const obj1 = {toString() {console.log("be string");return "_obj";},
};
const obj2 = {};
function foo() {}
const sym = Symbol();user[obj1] = "obj1 的 value";
user[obj2] = "obj2 的 value";
user[foo] = "foo 的 value";
user[sym] = "sym 的 value";
console.log(user); // { name: '下雪天的夏风', _obj: '关注一波' }/* 
be string
{_obj: 'obj1 的 value','[object Object]': 'obj2 的 value','function foo() {}': 'foo 的 value',[Symbol()]: 'sym 的 value'
}
*/

可以看到,对象默认的 toString() 方法执行结果比较特殊。

2,ts 中的索引签名

可以简单的理解:key 就是索引

基于在 js 中对象和函数等作为索引产生的特殊行为,ts 做了进一步的约束。
索引类型只能是:string | number | symbol,而value 可以是任意类型

  1. 其中string 也可以是模板字面量
interface HandleEvents {[key: `${string}Changed`]: () => void;
}
  1. 对象如果想作为索引,必须显示的调用.toString() 方法
let user: any = {};const obj1 = {toString() {return "_obj1";},
};// Type '{ toString(): string; }' cannot be used as an index type.ts(2538)
user[obj1] = "obj1 的 value";
user[obj1.toString()] = "ok";

索引签名就是在约束了索引(key)类型的基础上,统一定义了对象的 keyvalue 的类型

换句话说,索引签名可以在只知道keyvalue 的类型下,来统一定义对象的类型

规定:当声明一个索引签名后,所有成员都必须符合索引签名:

举例:

interface Sign1 {// key 只是占位符,随便什么单词都可以[key: string]: string;
}type Sign2 = {[index: number]: string | number;
};const foo: {[aaa: string]: { message: string }; // value 只能是1个对象,并且只有1个属性 message
} = {};

3,扩展索引签名定义的类型

  1. 可同时指定已确定的类型
// 必须包含 x 属性
interface Sign1 {[key: string]: number;x: number;
}interface Sign2 {[key: string]: number;y: string; // Error: 属性 y 的类型只能是'number'.ts(2411)
}
  1. 多个索引签名

在多个索引签名存在时,string 类型的索引最严格,书写时应该包含所有的 value 类型(假设为 All)。
其他类型的索引,对应的 value 类型只能是 All 的子级。

interface Sign3 {[key: string]: string | number | boolean; // 必须包括所用成员类型[index: symbol]: string;[index2: number]: number;
}
  1. 扩展

即便使用多个索引签名,也有覆盖不到的情况。

比如定义的对象中有一个list:string[] 字段,其他字段都不是string[] 类型。如果按照下面的写法,任何字段都可以是string[] 类型

interface Sign4 {[key: string]: string | number | string[]; // 必须包括所用成员类型
}

我们可以用索引签名+联合类型。

type Sign4 = {[key: string]: string | number;
} | { list: string[] }

2,与 Record 对比

先看下 Record 的定义

// node_modules\typescript\lib\lib.es5.d.ts
type Record<K extends keyof any, T> = {[P in K]: T;
};

在这里插入图片描述

鼠标放上去之后,会发现其实 keyvalue的类型的规则和索引签名的一致,也是:string | number | symbol,而value 可以是任意类型。

所以,二者并没有多大的区别,只是使用上略有不同而已。目前只发现的一个区别:

Record 的 key 可以为具体的类型,一般用于创建具有特定键值对的对象类型。

type Type1 = Record<'a | b | c', string>

3,遇到的问题

1,索引 key 的类型问题,keyof

type Sign = {[key: string]: boolean;
}
// string | number
type keys = keyof Signconst obj: Sign = {};
obj[2] = 123; // ok
obj["3"] = 123;

原因是:当数字作为 key 时,js 会隐式地将数字强制转换为字符串,ts 也会执行这种转换。

2,索引 key 的类型问题2:受具体定义的影响

这是我的提问

<script setup lang="ts">
interface NumberDictionary {[index: string]: string;
}const formInfo: NumberDictionary = {name: "john",want: "eat",
};Object.entries(formInfo).forEach(([key, value]) => {console.log(key, value);
});
</script>
<template><form><input v-for="(value, key) in formInfo" :name="key" :value="value" :key="key" type="text" /></form>
</template>

可以看到2个地方 key 的类型不一致:

在这里插入图片描述
在这里插入图片描述

原因:

  1. Object.entries 的类型声明
// node_modules\typescript\lib\lib.es2017.object.d.ts
entries<T>(o: { [s: string]: T } | ArrayLike<T>): [string, T][];

可以看到接受的就是 string 类型,相当于在 forEach 使用时,key 已经被断言为 string 类型了。

  1. v-for 的类型声明
// node_modules\@vue\runtime-core\dist\runtime-core.d.ts  第 1602 行
/*** v-for object*/
export declare function renderList<T>(source: T, renderItem: <K extends keyof T>(value: T[K], key: K, index: number) => VNodeChild)
: VNodeChild[];

可以看到 K extends keyof T,很熟悉!这就是上面遇到的第1个问题。
对上面这个例子来说,v-forkey 的类型就是 string | number

知道原因了,解决方法就有了,用Record 即可

interface NumberDictionary {[index: string]: string;
}
// ↓↓
type NumberDictionary = Record<string, string>

以上。


参考

索引签名-参考1

索引签名-参考2

索引签名-参考3

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/25666.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

uni-app:实现表格多选及数据获取

效果&#xff1a; 代码&#xff1a; <template><view><scroll-view scroll-x"true" style"overflow-x: scroll; white-space: nowrap;"><view class"table"><view class"table-tr"><view class&quo…

mysql高级三:sql性能优化+索引优化+慢查询日志

内容介绍 单表索引失效案例 0、思考题&#xff1a;如果把100万数据插入MYSQL &#xff0c;如何提高插入效率 &#xff08;1&#xff09;关闭自动提交&#xff0c;只手动提交一次 &#xff08;2&#xff09;删除除主键索引外其他索引 &#xff08;3&#xff09;拼写mysql可以执…

Typescript中的元组与数组的区别

Typescript中的元组与数组的区别 元组可以应用在经纬度这样明确固定长度和类型的场景下 //元组和数组类似&#xff0c;但是类型注解时会不一样//元组赋值的类型、位置、个数需要和定义的类型、位置、个数完全一致&#xff0c;不然会报错。 // 数组 某个位置的值可以是注解中的…

新能源电车交流充电桩控制主板的安全性维度

你是否想过&#xff0c;交流充电桩主板的安全性有多重要?它不仅关乎充电设备的寿命&#xff0c;还关乎电网的安全。今天我们就来探讨一下&#xff0c;如何从多个维度保证交流充电桩主板的安全性。 首先&#xff0c;交流充电桩主板采用多重安全保护技术&#xff0c;可以有效地保…

SM2算法的抗侧信道攻击

SM2 算法中底层模块抗侧信道 标量乘 ( [ k ] G [k]G [k]G) 运算过程中需要用到大量的倍点运算与点加运算。传统倍点运算与点加运算之间由于需要的运算次数不同&#xff0c;功耗存在明显区别&#xff0c;攻击者可以通过功耗波形特征分析密钥信息。传统算法如下图所示&#xff1a…

11. 使用tomcat中碰到的一些问题

文章目录 问题一&#xff1a;Tomcat的startup.bat启动后出现乱码问题二&#xff1a;一闪而退之端口占用问题三&#xff1a;非端口问题的一闪而退问题四&#xff1a;服务器的乱码和跨域问题问题五: 在tomcat\webapps\下创建文件夹为什么tomcat重启就会丢失问题六&#xff1a;Tom…

【C++】AVL(平衡二叉搜索树)树的原理及实现

文章目录 一、引言 二、AVL树的概念 三、AVL树的插入 3、1 AVL树的简单插入 3、2 旋转分类 3、2、1 新节点插入较高右子树的右侧&#xff1a;左单旋 3、2、2 新节点插入较高左子树的左侧&#xff1a;右单旋 3、2、3 新节点插入较高左子树的右侧&#xff1a;左右双旋&#xff08…

数据库执行新增时,字段写值错乱/字段值写反了 的问题

今天给表加了个字段&#xff0c;执行新增后查看表&#xff0c;发现数据库执行新增完成后&#xff0c;字段写值错乱了&#xff0c;表现为这两个字段的值写反了↓↓↓↓↓↓ 排查了xml中所有赋值的地方&#xff0c;全都没有问题 字段与属性的通用映射&#xff1a; <resultMap…

【已解决】Java 中使用 ES 高级客户端库 RestHighLevelClient 清理百万级规模历史数据

&#x1f389;工作中遇到这样一个需求场景&#xff1a;由于ES数据库中历史数据过多&#xff0c;占用太多的磁盘空间&#xff0c;需要定期地进行清理&#xff0c;在一定程度上可以释放磁盘空间&#xff0c;减轻磁盘空间压力。 &#x1f388;在经过调研之后发现&#xff0c;某服务…

编织人工智能:机器学习发展历史与关键技术全解析

文章目录 1. 引言1.1 机器学习的定义1.2 重要性和应用场景重要性应用场景 2. 机器学习的早期历史2.1 初期理论与算法感知机决策树 2.2 早期突破支持向量机神经网络初探 3. 21世纪初期的发展3.1 集成学习方法随机森林XGBoost 3.2 深度学习的崛起卷积神经网络&#xff08;CNN&…

css-4:元素水平垂直居中的方法有哪些?如果元素不定宽高呢?

1、背景 在开发中&#xff0c;经常遇到这个问题&#xff0c;即让某个元素的内容在水平和垂直方向上都居中&#xff0c;内容不仅限于文字&#xff0c;可能是图片或其他元素。 居中是一个非常基础但又是非常重要的应用场景&#xff0c;实现居中的方法存在很多&#xff0c;可以将这…

Spring IOC

◆ 传统Javaweb开发的困惑 ◆ IoC、DI和AOP思想提出 ◆ Spring框架的诞生 Spring | Home IOC控制反转&#xff1a;BeanFactory 快速入门 package com.xiaolin.service.Impl;import com.xiaolin.dao.UserDao; import com.xiaolin.service.UserService;public class UserServic…

Intel 4工艺太难了!酷睿Ultra终于突破5GHz

无论是14nm还是10nm&#xff0c;Intel这些年的新工艺都有一个通性&#xff1a;刚诞生的时候性能平平&#xff0c;高频率都上不去&#xff0c;只能用于笔记本移动端(分别对应5代酷睿、10代酷睿)&#xff0c;后期才不断成熟&#xff0c;比如到了13代酷睿就达到史无前例的6GHz。 接…

【Linux】守护进程

1 相关概念 1.1 守护进程的概念 守护进程也叫做精灵进&#xff0c;是运行在后台的一种特殊进程。它独立于控制终端并且可以周期性的执行某种任务或者处理某些发生的事件。 守护进程是非常有用的进程&#xff0c;在Linux当中大多数服务器用的就是守护进程。比如&#xff0c;web…

前端 select 标签如何创建下拉菜单?

聚沙成塔每天进步一点点 ⭐ 专栏简介⭐ 代码示例⭐ 代码讲解⭐ 写在最后 ⭐ 专栏简介 前端入门之旅&#xff1a;探索Web开发的奇妙世界 记得点击上方或者右侧链接订阅本专栏哦 几何带你启航前端之旅 欢迎来到前端入门之旅&#xff01;这个专栏是为那些对Web开发感兴趣、刚刚踏…

【网络基础知识铺垫】

文章目录 1 :peach:计算机网络背景:peach:1.1 :apple:网络发展:apple: 2 :peach:协议:peach:2.1 :apple:协议分层:apple:2.2 :apple:OSI七层模型:apple:2.3 :apple:TCP/IP模型:apple:2.4 :apple:TCP/IP模型与操作系统的关系:apple: 3 :peach:网络传输基本流程:peach:4 :peach:网…

MybatisPlus存在 sql 注入漏洞(CVE-2023-25330)解决办法

首先我们了解下这个漏洞是什么&#xff1f; MyBatis-Plus TenantPlugin 是 MyBatis-Plus 的一个为多租户场景而设计的插件&#xff0c;可以在 SQL 中自动添加租户 ID 来实现数据隔离功能。 MyBatis-Plus TenantPlugin 3.5.3.1及之前版本由于 TenantHandler#getTenantId 方法在…

DeviceNet主站网关转ETHERCAT连接ethercat总线伺服如何控制

大家好&#xff0c;今天要和大家分享一款自主研发的通讯网关——捷米JM-ECTM-DNT。这款产品可是解决了不同协议设备数据交换的麻烦问题&#xff0c;让我们一起来看看它的神奇之处吧&#xff01; 这款通讯网关有什么特别的呢&#xff1f;首先&#xff0c;它可以连接DEVICENET总…

火车头标题伪原创【php源码】

大家好&#xff0c;给大家分享一下python怎么读取文件中的数据&#xff0c;很多人还不知道这一点。下面详细解释一下。现在让我们来看看&#xff01; 火车头采集ai伪原创插件截图&#xff1a; python是一门非常火爆且相对易学的编程语言&#xff0c;应用在各种场景。许多人想学…

electron+vue3全家桶+vite项目搭建【13.1】ipc通信的使用,主进程与渲染进程之间的交互

文章目录 引入IPC通信[主/渲染]进程对应渲染进程>主进程代码测试测试效果 主进程>渲染进程代码测试测试效果 双向通信代码测试测试效果 引入 electron项目常常由一个主进程和多个渲染进程构成&#xff0c;渲染进程之间是隔离的&#xff0c;而所有渲染进程都和主进程共享…