typescript结构化类型应用两例
介绍
结构化类型是typescript类型系统的一个重要特性,如果不了解这个特性,则经常会被typescript的行为搞得一头雾水,导致我们期待的行为与实际的行为不一致。今天我们就来看两个例子。
不了解结构化类型的同学,可以先看看这篇:// 插入文章链接。
第一个例子
下面的代码定义了一个Person
类型
interface Person {
name: string;
age: number;
}
然后又定义了一个函数打印这个类型的对象
function printPerson(person: Person) {
console.log(`Name: ${person.name}, Age: ${person.age}`);
}
按道理来说,要调用这个函数,必须传递一个Person
类型的对象,但是你会发现,直接传一个对象进去也行。
printPerson({ name: "Alice", age: 30 });
这段代码没有报错,为什么呢?因为typescript的结构化类型系统认为,只要传入的对象包含了Person
类型所需的所有属性,就可以被认为是Person
类型。你甚至可以多加一些属性,比如:
printPerson({ name: "Alice", age: 30, location: "Wonderland" });
代码一样可以正常运行!
为什么?因为在typescript中,类型是基于结构
的,而不是基于名称的。只要对象的结构符合要求,就可以被认为是该类型。如果一个类型A包含了类型B的所有属性,那么类型A就可以被认为是类型B。在使用类型B的地方,就可以使用类型A代替。
第二个例子
还是以上面的Person
类型为例,假设我们要打印Person
对象中的所有属性,有的同学可能不假思索的写下如下代码:
interface Person {
name: string;
age: number;
}
const person: Person = { name: "Alice", age: 30 };
function printProperties(person: Person) {
for (const property in person) {
console.log(`${property}: ${person[property]}`);
}
}
printProperties(person);
但是这段代码却报错了:
TS7053: Element implicitly has an 'any' type because expression of type 'string' can't be used to index type 'Person'. No index signature with a parameter of type 'string' was found on type 'Person'.
当我第一次看到这个错误时,我只想撞墙,我哪里用any
了,这不是胡扯吗?但这不是对待错误的正确态度,这种错误如果不彻底解决,那么它就会一直困扰你,只有将它彻底击败,下次再遇到时才能得心应手!
仔细看一下这个报错,它大概描述了两件事情:
string
类型的值不能用来索引Person
类型。Person
类型没有定义索引签名。
其实这两件事本质上说的是一个问题,那就是在TypeScript中,只有在类型中显式定义了索引签名,才能使用string
类型的值来索引该类型。那么我们就给Person
类型添加一个索引签名:
方式一:为Person
类型添加索引签名
interface Person {
name: string;
age: number;
[key: string]: any; // 索引签名
}
[key: string]: any;
这行代码的意思是,Person
类型可以有任意数量的属性,属性名必须是字符串类型 ([key: string]
),属性值可以是任意类型(any
)。
现在我们再来运行printProperties
函数,就不会报错了。
方式二:使用keyof
关键字
坦白的说,为了一个遍历函数给Person
类型添加一个索引签名有点过于冗余了,其实我们可以使用另一个方法来解决这个问题,那就是使用keyof
关键字来获取Person
类型的所有属性名。
function printProperties(person: Person) {
for (const property in person) {
console.log(`${property}: ${person[property as keyof typeof person]}`);
}
}
来看这一句代码property as keyof typeof person
, 它的执行步骤是这样的:
- 先执行
typeof person
,得到Person
类型。 - 再执行
keyof Person
,得到Person
类型的所有属性名的联合类型 -name | age
。 - 最后使用
as
操作符将property
转换为这个联合类型。
这样做的好处是,property
的类型被限制为Person
类型的属性名,在本例中就是name
和age
这两个属性,绝不会超出这个范围,这样就可以安全地索引person
对象了。
眼力好的同学可能已经发现了,上面这个写法可以简化一下,property as keyof typeof person
可以简化为property as keyof Person
,因为person
的类型就是Person
,所以我们可以直接使用Person
类型来代替。这样可以节省一个typeof
操作符的使用。
方式三:使用Object.entries
当然,我们还可以使用Object.entries
方法来遍历对象的属性,这样就不需要担心索引签名的问题了。
function printProperty(person: Person) {
Object.entries(person).forEach(([key, value]) => {
console.log(`${key}: ${value}`);
});
}
分析一下这段代码:
Object.entries
方法会返回一个二维数组,其中每个元素又是一个数组,这个数组包含了对象的属性名和属性值。以上面的person
对象为例,Object.entries(person)
会返回[['name', 'Alice'], ['age', 30]]
,- 接下来的
forEach
方法会遍历这个数组,这里使用了一个数组解构操作符([key, value])
,将每个属性的名字赋值给key,属性的值赋值给value, - 最后使用
console.log
打印出来。
我比较喜欢方式三,简洁易懂,无需额外的操作。
今天就到这里了,觉得有用就点个关注吧,我们下次再见,我要去打弹弓了。
typescript结构化类型应用两例的更多相关文章
- TypeScript 学习笔记 — 类型兼容 (十)
目录 一.基本数据类型的兼容性 二.接口兼容性 三.函数的兼容性 四.类的兼容性 类的私有成员和受保护成员 五.泛型的兼容性 六.枚举的兼容性 标称类型简短介绍 TS 是结构类型系统(structur ...
- 结构化日志类库 ---- Serilog库
在过去的几年中,结构化日志已经大受欢迎.而Serilog是 .NET 中最著名的结构化日志类库 ,我们提供了这份的精简指南来帮助你快速了解并运用它. 0. 内容 设定目标 认识Serilog 事件和级 ...
- NumPy之:结构化数组详解
目录 简介 结构化数组中的字段field 结构化数据类型 创建结构化数据类型 从元组创建 从逗号分割的dtype创建 从字典创建 操作结构化数据类型 Offsets 和Alignment Field ...
- GO语言基础(结构+语法+类型+变量)
GO语言基础(结构+语法+类型+变量) Go语言结构 Go语言语法 Go语言类型 Go语言变量 Go 语言结构 Go 语言的基础组成有以下几个部分: 包声明 引入包 函数 变量 语句 &a ...
- NoSQL生态系统——类似Bigtable列存储,或者Dynamo的key存储(kv存储如BDB,结构化存储如redis,文档存储如mongoDB)
摘自:http://www.ituring.com.cn/article/4002# NoSQL系统的数据操作接口应该是非SQL类型的.但在NoSQL社区,NoSQL被赋予了更具有包容性的含义,其意为 ...
- 详解Google-ProtoBuf中结构化数据的编码
本文的主要内容是google protobuf中序列化数据时用到的编码规则,但是,介绍具体的编码规则之前,我觉得有必要先简单介绍一下google protobuf.因此,本文首先会介绍一些google ...
- 深入研究 Win32 结构化异常处理(好多相关文章)
摘要 就像人们常说的那样,Win32 结构化异常处理(SEH)是一个操作系统提供的服务.你能找到的所有关于 SEH 的文档讲的都是针对某个特定编译器的.建立在操作系统层之上的封装库.我将从 SEH 的 ...
- 深入研究 Win32 结构化异常处理(作者博客有许多SEH的研究文章)
摘要 就像人们常说的那样,Win32 结构化异常处理(SEH)是一个操作系统提供的服务.你能找到的所有关于 SEH 的文档讲的都是针对某个特定编译器的.建立在操作系统层之上的封装库.我将从 SEH 的 ...
- DeepLearning.ai学习笔记(三)结构化机器学习项目--week2机器学习策略(2)
一.进行误差分析 很多时候我们发现训练出来的模型有误差后,就会一股脑的想着法子去减少误差.想法固然好,但是有点headlong~ 这节视频中吴大大介绍了一个比较科学的方法,具体的看下面的例子 还是以猫 ...
- 结构化您的Python工程
我们对于"结构化"的定义是您关注于怎样使您的项目最好地满足它的对象性,我们 需要去考虑如何更好地利用Python的特性来创造简洁.高效的代码.在实践层面, "结构化&qu ...
随机推荐
- FDMemtable如何增加一条自身复制的记录
procedure TFrame_Bill.CopyARecord; var lAFDmemtable : TFDMemTable; begin {$REGION '增加一条复制的记录'} try l ...
- Unity/Auto Layout -- 理解Layout Elements(布局元素)
- Selenium+pytest 页面对象模型框架
下载地址:https://gitee.com/xiaopo1998/web_ui_test.git Selenium 页面对象模型框架使用说明 本框架基于 Selenium WebDriver 实现了 ...
- Asp.net mvc基础(八)Layout页面的使用
Layout页面相当于母版页. 使用步骤如下: 1.创建MVC5布局页 @RenderBody()渲染正文部分 @ViewBag.Title表示标题内容 也可以自己定义渲染的部分:比如在布局页中添加@ ...
- python,爬取小说网站小说内容,同时每一章存在不同的txt文件中
思路,第一步小说介绍页获取章节地址,第二部访问具体章节,获取章节内容 具体如下:先获取下图章节地址 def stepa(value,headers): lit=[] response = reques ...
- MySQL 中使用索引一定有效吗?如何排查索引效果?
MySQL 中使用索引一定有效吗?如何排查索引效果? 虽然索引是提升 MySQL 查询性能的常见手段,但并不是所有情况下索引都会有效.索引的使用取决于查询条件.数据分布.索引设计等多个因素.如果索引未 ...
- Java编程之面向对象
一.面向对象 1.定义 (1)类:描述的是具有共性的一类事物 (2)对象:一个个具备了类的特点和功能的个体 (3)面向对象:要完成某件事,首先要先有对象,然后直接调用这个对象的响应功能 2.成员变量: ...
- HTML用JS导出Excel的五种方法,无需js-xlsx库
原文地址:https://blog.csdn.net/aa122273328/article/details/50388673 这五种方法前四种方法只支持IE浏览器,最后一个方法支持当前主流的浏览器( ...
- 倍增 & Tarjan 求解LCA
什么是LCA? 假设我们有一棵树: 1 / \ 2 3 / \ / 4 5 6 对于 \(2\) 和 \(6\) 的LCA,就是最近公共祖先,即为距离 \(2\) 和 \(6\) 最近的两个节点公有的 ...
- UnoCSS原子CSS引擎
UnoCSS是一款原子化的即时按需 CSS 引擎,其中没有核心实用程序,所有功能都是通过预设提供的.默认情况下UnoCSS应用通过预设来实现相关功能. UnoCSS中文文档: https://www. ...