第三节:TypeScript对象类型

 我来答
科创17
2022-06-24 · TA获得超过5900个赞
知道小有建树答主
回答量:2846
采纳率:100%
帮助的人:175万
展开全部

在 JavaScript 中,我们分组和传递数据的基本方式是通过对象。在 TypeScript 中,我们通过 对象类型 来表示它们。

而TypeScript的核心原则之一是对值所具有的的结构进行类型检查,


之前的数据类型中已经了解,如何限定变量的类型

例如:


如果变量的值不是基本数据类型的值,而是一个对象,可以使用 object 类型



这种写法只能限定变量是object 类型, 但是没法明确表明或限定对象内部属性以及值类型,

也就是说示例中name可是是任意数据类型;属性也不限定于 name 和 age

如果要限定对象属性值的类型,就需要使用字面量的方式进行类型注释

这样的写法虽然达到了限定对象内部结构, 但同时也带来了另外的问题,如属性过多,或多次复用相同类型注释.

因此可以定义接口或 类型别名来定义统一的对象属性限制


通过接口命名对象类型


或者使用类型别名来命名对象类型

但是也需要注意到,在给使用了接口和类型别名时, 变量值接受对象中的属性必须和接口或类型别名中定义的属性一致.,多了少了编译时都会报错


为了让对象类型更具灵活性, 对象类型中每个属性都可以指定几件事:


很多时候,在处理对象类型的时候, 某些属性可能并不一定存在. 这个时候就需要用到可选属性.

可选属性通过在属性名称末尾添加 ? 来将这些属性标记为可选

例如:

可选属性在进行检测时,可选属性在实现上可有可无,这样就提升了对象类型使用的灵活性.

例如:


在TypeScript中对象属性也可以标记为 readonly 只读属性

只读属性虽然不会在运行时更改任何行为.但在类型检查期间无法写入只读标记的属性

通过在属性名前添加 readonly 来标记只读属性

例如:

此时 name 属性标记为只读属性, 当你尝试修改只读属性值时, TypeScript 报错,提示你不可修改

使用 readonly 修饰符并不一定意味着一个值完全不可修改, 也就是说属性属性值是一个引用类型的值,比如对象

readonly 只是表示当前属性本身不能被重写, 但属性值是引用类型, 引用类型内部的值是完全可变的

例如:

示例中只读属性 friend 内部的属性 name 被修改了, 没有任何报错.

因为TypeScript在检查这些类型是否兼容时不会考虑两种类型内部的属性是否有 readonly 标记存在, 所以 readonly 属性也可以通过别名来更改, 也就是说将有只读属性的类型重新分配给没有只读属性的类型


有的时候你并不提前知道类型属性的所有属性名, 但你确实知道属性值的类型

在这样的情况下, 你可以使用索引签名来描述可能值的类型,

例如:

示例中所以签名的意思,表示使用 number 类型的索引获取值时,返回 string 类型

TypeScript索引签名可以同时支持两种类型的索引器.

虽然字符串索引签名是描述'字典'模式的强大方式, 但TypeScript 还是强制所有的属性与其返回的类型匹配

例如:

示例中, age 属性的类型是 number 类型, 将会出现错误,因为与索引签名冲突,

其实也很好理解, 因为在使用 age 属性时, 无论通过, obj.age , 还是 obj["age"] , 其都符合索引签名的模式, 返回的值类型应该是 string 类型, 可是你有明确的声明了 age 属性的返回值是明确的 number 类型

此时TypeScript不知道使用索引签名的规则来检查值类型,还是具体罗列 age 属性的类型来检查值类型


这种问题,可以通过给索引签名使用联合类型解决


最后你 还可以在索引签名上使用只读属性 readonly , 表示不可以给索引分配值

例如:只读索引签名


在实际使用时,一个类型有可能是其他类型的具体版本的类型很常见,

简单说就是, 一个类型只有另外一个类型中的部分信息

例如:

有一下两个类型:

人员基本信息,包含姓名,年纪信息

具体学生信息: 包含除了姓名,年纪外还有学号,班级等信息

示例中, StudentPerson 包含 Person 所有的属性信息, 也可以说是 Person 类型更详细的类型,

试想一下,如果每个定义包含 name , age 属性以及其他不同属性类型时,我们都像示例中把 name , age 属性重新定义一遍.

这样的使用方式会导致 name , age 属性大量重复


解决这样重复声明一个类型中所有的属性,我们就可以使用 extends 关键字扩展原有类型, 并添加新的属性

关键字 extends 允许我们有效的从其他命名类型复制成员, 并添加我们想要的新成员


同样 interface 接口也允许从多个接口中扩展新的类型

这样我们就可以使用 WorkPerson 接口来注释一个具有姓名,年纪, 工作信息,工号属性对象的类型


interface 允许我们通过 extends 扩展其他类型来构建新的类型

TypeScript中还为类型别名提供了另外一种称之为交叉类型的类型扩展方式. 主要用于组合现有类型

使用 & 运算符定义交叉类型

示例中,通过交叉类型组合 Colorful 并 Circle 生成一个新的类型别名,类型别名同时具有前两个类型的所有属性


也可以在类型注释的时候使用交叉类型


理解两者的主要区别,方便我们在使用时做出取舍


通用对象类型:就是需要定义一个可以通用类型,

例如:定义一个Box类型,具有 contents 属性, 但是属性的值可能是 string , number , 等各种类型

首先会想到的是属性值类型使用联合类型

但联合类型也仅仅是罗列我们已知的类型, 在使用场景下可能并不通用, 例如值也有可能是其他对象类型呢


此时也许会考虑 any 任何类型

any类型可以工作,但是可能会导致意外事故发生


也可以尝试定义 unknown 类型

使用unknown类型就意味着我们需要进行类型检查,或者使用类型断言


不过 unknow 也不是特别安全, 比较安全的做法是为每一种类型添加一个接口

但这意味着如果是给函数参数使用, 我们需要创建不同函数或函数重载, 才能对这些进行操作

这样的处理方式不仅繁琐, 而且之后需要需要新的类型还需要引入新的类型和重载, 因为我们contents类型和重载实际上都是相同的,


最好的处理方式,就是我们创建一个声明类型参数的泛型,

其实就是将类型定义为像函数参数或变量一样, 类型参数就可以在多个地方使用, 通过传递具体类型,让使用类型参数的地方全部指代当前具体类型

此时当我们在使用 Box 类型注释时,必须给出一个类型参数来代替 Type

此时会将Box视为类型模板,其中 Type 为占位符将被其他类型替换,


Box 类型可以重复使用, Type 可以用任何类型代替, 这意味着当我们需要一个新类型 Box 是, 我们根本不要在 声明一个新的 Box 类型, 我们只需要传递不同的类型替换 Type 即可


这也意味着,如果将类型用在函数参数上,我们可以通过使用泛型函数来避免重载

示例中, 我们并没有限定obj的类型, 但是在传递参数后, TypeScript根据入参推断出 Type 是一个string 类型, 因此函数的第二个参数也必须是一个字符串类,否则TypeScript将发出错误警告

例如:如下调用函数


类型的别名也是可以通用的

例如

Box 接口也可以使用类型别名来替换


由于类型别名与接口不同,类型别名不仅仅可以描述对象,还可以使用类型别名来编写其他类型的通用帮助类型

已赞过 已踩过<
你对这个回答的评价是?
评论 收起
迈杰
2024-11-30 广告
GWAS,即全基因组关联分析,是一种强大的遗传学研究方法。它通过对大规模群体的DNA变异进行系统性扫描,寻找与特定性状(如疾病易感性、药物反应等)相关联的遗传变异。在迈杰转化医学研究(苏州)有限公司,我们利用先进的GWAS技术,挖掘疾病相关... 点击进入详情页
本回答由迈杰提供
推荐律师服务: 若未解决您的问题,请您详细描述您的问题,通过百度律临进行免费专业咨询

为你推荐:

下载百度知道APP,抢鲜体验
使用百度知道APP,立即抢鲜体验。你的手机镜头里或许有别人想知道的答案。
扫描二维码下载
×

类别

我们会通过消息、邮箱等方式尽快将举报结果通知您。

说明

0/200

提交
取消

辅 助

模 式