Typescript - 索引签名

news2024/9/24 11:31:43

目录

  • 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 Sign

const 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.coloradmin.cn/o/839255.html

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

相关文章

CADintosh X for mac CAD绘图软件2D CAD 程序 兼容 M1

CADintosh X for Mac是一个功能强大的2D CAD绘图程序&#xff0c;专为Mac用户设计。它由Lemke Software开发&#xff0c;提供了一套丰富的工具和功能&#xff0c;使用户能够轻松创建高质量的技术图纸&#xff0c;平面图和设计。 CADintosh X for Mac具有直观的用户界面&#x…

Python3 处理PDF之PyMuPDF 入门

PyMuPDF 简介 PyMuPDF是一个用于处理PDF文件的Python库&#xff0c;它提供了丰富的功能来操作、分析和转换PDF文档。这个库的设计目标是提供一个简单易用的API,使得开发者能够轻松地在Python程序中实现PDF文件的各种操作。 PyMuPDF的主要特点如下&#xff1a; 跨平台兼容性&a…

【分布式系统】聊聊服务调度

什么是服务治理 对于程序员来说的话&#xff0c;把功能按照一定的设计进行开发上线之后&#xff0c;其实并不够&#xff0c;在未来的时间内&#xff0c;其实还需要做好功能的维护工作&#xff0c;而维护项目的成本远远高于开发出一个软件的成本。 对于功能开发起来期来说&am…

ensp-GVRP服务

ensp-GVRP服务 日期&#xff1a;6-26 &#x1f4ce;GVRP实验.zip&#x1f4ce;GVRP服务.docx

无涯教程-Perl - 环境配置

在开始编写Perl程序之前&#xff0c;让我们了解如何设置我们的Perl环境。 您的系统更有可能安装了perl。只需尝试在$提示符下给出以下命令- $perl -v 如果您的计算机上安装了perl&#xff0c;那么您将收到以下消息: This is perl 5, version 16, subversion 2 (v5.16.2) b…

谁更适合搭配甜点显卡?i7-13700KF、锐龙7 7800X3D对比:游戏相当 生产力Intel强了50%...

一、前言&#xff1a;如果搭配2000元甜点显卡 i7-13700KF和锐龙7 7800X3D谁更有性价比&#xff1f; 现在AMD最受欢迎的处理器无疑是拥有96MB三级缓存的锐龙7 7800X3D&#xff0c;这是一颗专为游戏而生的处理器。 Intel这边&#xff0c;i7-13700KF以略高于i5-13600K的售价&#…

python:卡尔曼和贝叶斯滤波器

本文分享一个Filerpy的说明文档和代码示例文档&#xff0c;有关于 Python 中的卡尔曼和贝叶斯滤波器。该方法可以应用于气象遥感等领域。 说明文档&#xff1a;https://filterpy.readthedocs.io/en/latest/kalman/KalmanFilter.html 参考代码链接&#xff1a;https://nbviewer.…

conda install 和pip install有什么区别?

本篇为分享贴&#xff0c;截图部分选自知乎&#xff0c;部分选自csdn&#xff0c;文字内容是结合自己实践进行总结。 环境引用的包在哪&#xff1f; 首先&#xff0c;一条命令&#xff1a; python -m site 这条命令可以定位引用的包在哪里 &#xff0c;当然也可以自己设置默认…

K8s中的Secret

Secret作用&#xff1a;加密数据存在etcd里面&#xff0c;让pod容器以挂载Volume方式进行访问。场景&#xff1a;凭据

基于Open3D的点云处理14-法向量

法向量 计算法向量的接口函数&#xff1a; Open3d使用estimate_normals函数来计算法向量。其参数设置Open3d提供了3中参数搜索的方法&#xff08;所有计算的法向量模长为1&#xff09;&#xff1a; open3d.geometry.KDTreeSearchParamKNN(knn20) # 计…

win11设置管理员权限

【win11家庭版怎么找管理员权限&#xff0c;怎么找gpedit】 win11家庭版怎么找管理员权限&#xff0c;怎么找gpedit_哔哩哔哩_bilibili echo offpushd "%~dp0"dir /b C:\Windows\servicing\Packages\Microsoft-Windows-GroupPolicy-ClientExtensions-Package~3*.mum …

【雕爷学编程】Arduino动手做(185)---WK104 亚克力机械爪

收了一套 亚克力机械爪的散件&#xff0c;准备尝试组装一下。 All parts 2 left claw 2 right claw 4 half claw 2 plate fixer 双通铜柱 Double copper column 铜柱 copper pillar 螺母 Nut 螺丝 Screw Prepare several parts of the picture and start assembling the l…

小蜗语音1.2 文本生成字幕 文本生成语音配音

1、文本转字幕&#xff0c;可以把一部小说直接生成字幕 2、文本转语音&#xff0c;可以直接把一部小说或者字幕文件生成语音&#xff0c;并且新生成的语音和字幕一一对应 链接&#xff1a;https://pan.baidu.com/s/1X_rY4Wjkk2cWqsFcu4JSHA?pwdvtpm 提取码&#xff1a;vtpm

S7-200SMART与ET200SP远程IO模块进行PROFINET通信的具体方法

S7-200SMART与ET200SP远程IO模块进行PROFINET通信的具体方法 使用前提: 只有标准型且固件版本为V2.4及以上的S7-200 SMART CPU才支持 PROFINET 控制器功能。 S7-200 SMART 作 PROFINET 控制器最多可带8个 IO 设备(例如:远程 IO、阀岛、变频器、伺服和机器人等)。 本例中以 …

剑指offer15.二进制中1的个数

第一种方法是将n不断与2的i次方相与&#xff0c;如果n的2的i次方的位置上是1&#xff0c;相与的结果就是1&#xff0c;res&#xff0c;最后返回res即可。 public class Solution {// you need to treat n as an unsigned valuepublic int hammingWeight(int n) {int res 0;fo…

Jmeter录制HTTPS脚本

Jmeter录制HTTPS脚本 文章目录 添加“HTTP代理服务器”设置浏览器代理证书导入存在问题 添加“HTTP代理服务器” 设置浏览器代理 保持端口一致 证书导入 点击一下启动让jmeter自动生成证书&#xff0c;放在bin目录下&#xff1a; 打开jmeter的SSL管理器选择刚刚生成的证书&…

Rabbitmq的消息确认

配置文件 spring:rabbitmq:publisher-confirm-type: correlated #开启确认回调publisher-returns: true #开启返回回调listener:simple:acknowledge-mode: manual #设置手动接受消息消息从生产者到交换机 无论消息是否到交换机ConfirmCallback都会触发。 Resourceprivate Rabb…

LeetCode--剑指Offer75(3)

目录 题目描述&#xff1a;剑指 Offer 20. 表示数值的字符串&#xff08;中等&#xff09;题目接口解题思路什么是有限状态自动机&#xff1f;如何使用&#xff1f; 代码 PS: 题目描述&#xff1a;剑指 Offer 20. 表示数值的字符串&#xff08;中等&#xff09; 请实现一个函数…

支付宝蜻蜓设备abs调试

蜻蜓设备系统日志调试 1、蜻蜓设备进入开发者模式 长按关键键直到屏幕上出现设置按钮&#xff0c;点击设置按钮&#xff0c;选择关于本机&#xff0c;找到系统版本&#xff0c;连续点击8次&#xff0c;选择进入调试模式 2、找到小程序容器&#xff0c;连续点击8次&#xff0…

自己实现Linux 的 cp指令

cp指令 Linux的cp指令就是复制文件&#xff1a; cp: 拷贝(cp 拷贝的文件 要拷贝到的地址或文件)&#xff0c;cp b.c test.c 将b.c拷成test.c的一个新文件 Linux 系统初识_mjmmm的博客-CSDN博客 实现思路 打开源文件读文件内容到缓冲区创建新文件将读到的文件内容全部写入新文…