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 ...
随机推荐
- Docker Swarm Mode 的容器资源回收问题
问题描述 Docker Swarm Mode 中 service 的update/scale等操作都会形成残留的容器和镜像,会造成一定程度的磁盘空间占用及缓存占用等问题... 解析 存在即合理,残留的 ...
- ArrayBlockingQueue的take()底层原理
一.ArrayBlockingQueue 的 take() 方法的底层源码的详细介绍 ArrayBlockingQueue 是 Java 并发包 (java.util.concurrent) 中的一个 ...
- java基础之接口、多态
一.接口:是Java语言中一种引用类型[组数.类也是引用类型],内部主要就是封装了方法, 包括(抽象方法.默认方法.静态方法.私有方法) 格式: public interface 接口名称 { // ...
- Java编程之容器类
一.ArrayList 1.创建ArrayList对象 ArrayList<String> arr=new ArrayList<>(); //添加<>的为泛型 // ...
- 一天 Star 破万的开源项目「GitHub 热点速览」
虽然现在市面上的 AI 编程助手已经"琳琅满目",但顶流就是顶流!OpenAI 新开源的轻量级编程助手 Codex,发布不到 24 小时 Star 数就轻松破万!姗姗来迟的 Ope ...
- windows系统如何开启远程连接
一.RDP远程桌面介绍 RDP远程桌面即远程桌面系统(Remote Desktop Protocol),是内置于windows系统的网络通信协议.通过RDP,用户可以远程登录到运行windows系统的 ...
- chrome “从 Google 获取图片说明”
右键菜单"从 Google 获取图片说明"多余去掉. 设置-高级-使用硬件加速模式(如果可用)-关闭 在用户使用上firefox完胜chrome,但是firefox的开发人员工具相 ...
- Java Annotation认知(包括框架图、详细介绍、示例说明)--转载
转载地址:https://www.cnblogs.com/skywang12345/p/3344137.html
- XXL-CACHE v1.2.0 | 多级缓存框架
Release Notes 1.[增强]多序列化协议支持:针对L2缓存,组件化抽象Serializer,可灵活扩展更多序列化协议: 2.[优化]移除冗余依赖,精简Core体积: XXL- CACHE ...
- K-means 基本流程 Demo
也是单纯搬个砖, 记个笔记, K-Means 最近是有在用的, 当然之前也有用的, 也是掉包来弄的, 已经很少会去自己写了, 这里的目的, 也是为了自己, 后面再遇到可以复制粘贴. 对, 情况就是这样 ...