本文目录:
- 1、第三节:TypeScript对象类型
- 2、走进 Typescript 数据结构(队列)
- 3、TypeScript 入门指南
第三节:TypeScript对象类型
在 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 接口也可以使用类型别名来替换
由于类型别名与接口不同,类型别名不仅仅可以描述对象,还可以使用类型别名来编写其他类型的通用帮助类型
走进 Typescript 数据结构(队列)
项目做了,搬砖搬类。想一想怎么能高效地搬砖呢?得有点技巧,数据结构以及应用场景一定的熟练。在 coding 之前一定要先画流程图,想好了再做。
有关数据结构可以建立在抽象行为来进行划分,具有这样行为的我们就认为他属于这种数据结构。
那么什么是队列呢?
队列是遵循FIFO(先进先出)原则的一组有序的项,只要满足了先进先出这种行为我们就认为他是队列
list = dequeue(enqueue(element));
队列在我们生活场景很多,排队购票什么的。
TypeScript 入门指南
新系列 深入浅出TypeScript 来了,本系列至少20+篇。本文为第一篇,来介绍一下TypeScript 以及常见的类型。
TypeScript是一门由微软推出的开源的、跨平台的编程语言。它是JavaScript的超集,扩展了 JavaScript 的语法,最终会被编译为JavaScript代码。
TypeScript的主要特性:
TypeScript 主要是为了实现以下两个目标:
下面就来看看这两个目标是如何实现的。
为什么要给JavaScript加上类型呢?
我们知道,JavaScript是一种轻量级的解释性脚本语言。也是弱类型、动态类型语言,允许隐式转换,只有运行时才能确定变量的类型。正是因为在运行时才能确定变量的类型,JavaScript代码很多错误在运行时才能发现。TypeScript在JavaScript的基础上,包装了类型机制,使其变身成为 静态类型 语言。在 TypeScript 中,不仅可以轻易复用 JavaScript 的代码、最新特性,还能使用可选的静态类型进行检查报错,使得编写的代码更健壮、更易于维护。
下面是 JavaScript 项目中最常见的十大错误,如果使用 TypeScript,那么在 编写阶段 就可以发现并解决很多 JavaScript 错误了:
类型系统能够提高代码的质量和可维护性,经过不断的实践,以下两点尤其需要注意:
可以认为,在所有操作符之前,TypeScript 都能检测到接收的类型(在代码运行时,操作符接收的是实际数据;在静态检测时,操作符接收的则是类型)是否被当前操作符所支持。当 TypeScript 类型检测能力覆盖到所有代码后,任意破坏约定的改动都能被自动检测出来,并提出类型错误。因此,可以放心地修改、重构业务逻辑,而不用担忧因为考虑不周而犯下低级错误。
在一些语言中,类型总是有一些不必要的复杂的存在方式,而 TypeScript 尽可能地降低了使用门槛,它是通过如下方式来实现的。
TypeScript 与 JavaScript 本质并无区别,我们可以将 TypeScipt 理解为是一个添加了类型注解的 JavaScript,为JavaScript代码提供了编译时的类型安全。
实际上,TypeScript 是一门“ 中间语言 ”,因为它最终会转化为JavaScript,再交给浏览器解释、执行。不过 TypeScript 并不会破坏 JavaScript 原有的体系,只是在 JavaScript 的基础上进行了扩展。
准确的说,TypeScript 只是将JavaScript中的方法进行了标准化处理:
这段代码在TypeScript中就会报错,因为TS会知道a是一个数字类型,不能将其他类型的值赋值给a,这种类型的推断是很有必要的。
上面说了,TypeScript会尽可能安全的推断类型。我们也可以使用类型注释,以实现以下两件事:
在一些语言中,类型总是有一些不必要的复杂的存在方式,而 TypeScript 的类型是结构化的。比如下面的例子中,函数会接受它所期望的参数:
为了便于把 JavaScript 代码迁移至 TypeScript,即使存在编译错误,在默认的情况下,TypeScript 也会尽可能的被编译为 JavaScript 代码。因此,我们可以将JavaScript代码逐步迁移至 TypeScript。
虽然 TypeScript 是 JavaScript 的超集,但它始终紧跟ECMAScript标准,所以是支持ES6/7/8/9 等新语法标准的。并且,在语法层面上对一些语法进行了扩展。TypeScript 团队也正在积极的添加新功能的支持,这些功能会随着时间的推移而越来越多,越来越全面。
虽然 TypeScript 比较严谨,但是它并没有让 JavaScript 失去其灵活性。TypeScript 由于兼容 JavaScript 所以灵活度可以媲美 JavaScript,比如可以在任何地方将类型定义为 any(当然,并不推荐这样使用),毕竟 TypeScript 对类型的检查严格程度是可以通过 tsconfig.json 来配置的。
在搭建TypeScript环境之前,先来看看适合TypeScript的IDE,这里主要介绍Visual Studio Code,笔者就一直使用这款编辑器。
VS Code可以说是微软的亲儿子了,其具有以下优势:
因为 VS Code 中内置了特定版本的 TypeScript 语言服务,所以它天然支持 TypeScript 语法解析和类型检测,且这个内置的服务与手动安装的 TypeScript 完全隔离。因此, VS Code 支持在内置和手动安装版本之间动态切换语言服务,从而实现对不同版本的 TypeScript 的支持。
如果当前应用目录中安装了与内置服务不同版本的 TypeScript,我们就可以点击 VS Code 底部工具栏的版本号信息,从而实现 “use VS Code's Version” 和 “use Workspace's Version” 两者之间的随意切换。
除此之外,VS Code 也基于 TypeScript 语言服务提供了准确的代码自动补全功能,并显示详细的类型定义信息,大大的提升了我们的开发效率。
1)全局安装TypeScript:
2)初始化配置文件:
执行之后,项目根目录会出现一个 tsconfig.json 文件,里面包含ts的配置项(可能因为版本不同而配置略有不同)。
可以在 package.json 中加入script命令:
3)编译ts代码:
TSLint 是一个通过 tslint.json 进行配置的插件,在编写TypeScript代码时,可以对代码风格进行检查和提示。如果对代码风格有要求,就需要用到TSLint了。其使用步骤如下: (1)在全局安装TSLint:
(2)使用TSLint初始化配置文件:
执行之后,项目根目录下多了一个 tslint.json 文件,这就是TSLint的配置文件了,它会根据这个文件对代码进行检查,生成的 tslint.json 文件有下面几个字段:
这些字段的含义如下;
在说TypeScript数据类型之前,先来看看在TypeScript中定义数据类型的基本语法。
在语法层面,缺省类型注解的 TypeScript 与 JavaScript 完全一致。因此,可以把 TypeScript 代码的编写看作是为 JavaScript 代码添加类型注解。
在 TypeScript 语法中,类型的标注主要通过类型后置语法来实现:“ 变量: 类型 ”
在 JavaScript 中,原始类型指的是 非对象且没有方法 的数据类型,包括:number、boolean、string、null、undefined、symbol、bigInt。
它们对应的 TypeScript 类型如下:
JavaScript原始基础类型TypeScript类型 numbernumber booleanboolean stringstring nullnull undefinedundefined symbolsymbol bigIntbigInt
需要注意 number 和 Number 的区别:TypeScript中指定类型的时候要用 number ,这是TypeScript的类型关键字。而 Number 是 JavaScript 的原生构造函数,用它来创建数值类型的值,这两个是不一样的。包括 string 、 boolean 等都是TypeScript的类型关键字,而不是JavaScript语法。
TypeScript 和 JavaScript 一样,所有数字都是 浮点数 ,所以只有一个 number 类型。
TypeScript 还支持 ES6 中新增的二进制和八进制字面量,所以 TypeScript 中共支持 2、8、10和16 这四种进制的数值:
字符串类型可以使用单引号和双引号来包裹内容,但是如果使用 Tslint 规则,会对引号进行检测,使用单引号还是双引号可以在 Tslint 规则中进行配置。除此之外,还可以使用 ES6 中的模板字符串来拼接变量和字符串会更为方便。
类型为布尔值类型的变量的值只能是true或者false。除此之外,赋值给布尔值的值也可以是一个计算之后结果为布尔值的表达式:
在 JavaScript 中,undefined和 null 是两个基本数据类型。在 TypeScript 中,这两者都有各自的类型,即 undefined 和 null,也就是说它们既是实际的值,也是类型。这两种类型的实际用处不是很大。
注意,第一行代码可能会报一个tslint的错误: Unnecessary initialization to 'undefined' ,就是不能给一个变量赋值为undefined。但实际上给变量赋值为undefined是完全可以的,所以如果想让代码合理化,可以配置tslint,将" no-unnecessary-initializer "设置为 false 即可。
默认情况下,undefined 和 null 是所有类型的子类型,可以赋值给任意类型的值,也就是说可以把 undefined 赋值给 void 类型,也可以赋值给 number 类型。当在 tsconfig.json 的"compilerOptions"里设置为 "strictNullChecks": true 时,就必须严格对待了。这时 undefined 和 null 将只能赋值给它们自身或者 void 类型。这样也可以规避一些错误。
BigInt是ES6中新引入的数据类型,它是一种内置对象,它提供了一种方法来表示大于 2- 1 的整数,BigInt可以表示任意大的整数。
使用 BigInt 可以安全地存储和操作大整数,即使这个数已经超出了JavaScript构造函数 Number 能够表示的安全整数范围。
我们知道,在 JavaScript 中采用双精度浮点数,这导致精度有限,比如 Number.MAX_SAFE_INTEGER 给出了可以安全递增的最大可能整数,即 2- 1 ,来看一个例子:
可以看到,最终返回了true,这就是超过精读范围造成的问题,而 BigInt 正是解决这类问题而生的:
这里需要用 BigInt(number) 把 Number 转化为 BigInt ,同时如果类型是 BigInt ,那么数字后面需要加 n 。
在TypeScript中, number 类型虽然和 BigInt 都表示数字,但是实际上两者类型是完全不同的:
symbol我们平时用的比较少,所以可能了解也不是很多,这里就详细来说说symbol。
symbol 是 ES6 新增的一种基本数据类型,它用来表示独一无二的值,可以通过 Symbol 构造函数生成。
注意:Symbol 前面不能加 new关键字,直接调用即可创建一个独一无二的 symbol 类型的值。
可以在使用 Symbol 方法创建 symbol 类型值的时候传入一个参数,这个参数需要是一个字符串。如果传入的参数不是字符串,会先自动调用传入参数的 toString 方法转为字符串:
上面代码的第三行可能会报一个错误:This condition will always return 'false' since the types 'unique symbol' and 'unique symbol' have no overlap. 这是因为编译器检测到这里的 s1 === s2 始终是false,所以编译器提醒这代码写的多余,建议进行优化。
上面使用Symbol创建了两个symbol对象,方法中都传入了相同的字符串,但是两个symbol值仍然是false,这就说明了 Symbol 方法会返回一个独一无二的值。Symbol 方法传入的这个字符串,就是方便我们区分 symbol 值的。可以调用 symbol 值的 toString 方法将它转为字符串:
在TypeScript中使用symbol就是指定一个值的类型为symbol类型:
在ES6中,对象的属性是支持表达式的,可以使用于一个变量来作为属性名,这对于代码的简化有很多用处,表达式必须放在大括号内:
symbol 也可以作为属性名,因为symbol的值是独一无二的,所以当它作为属性名时,不会与其他任何属性名重复。当需要访问这个属性时,只能使用这个symbol值来访问(必须使用方括号形式来访问):
在使用obj.name访问时,实际上是字符串name,这和访问普通字符串类型的属性名是一样的,要想访问属性名为symbol类型的属性时,必须使用方括号。方括号中的name才是我们定义的symbol类型的变量name。
使用 Symbol 类型值作为属性名,这个属性是不会被 for…in遍历到的,也不会被 Object.keys() 、 Object.getOwnPropertyNames() 、 JSON.stringify() 等方法获取到:
虽然这些方法都不能访问到Symbol类型的属性名,但是Symbol类型的属性并不是私有属性,可以使用 Object.getOwnPropertySymbols 方法获取对象的所有symbol类型的属性名:
除了这个方法,还可以使用ES6提供的 Reflect 对象的静态方法 Reflect.ownKeys ,它可以返回所有类型的属性名,Symbol 类型的也会返回:
Symbol 包含两个静态方法, for 和 keyFor 。 1)Symbol.for()
用Symbol创建的symbol类型的值都是独一无二的。使用 Symbol.for 方法传入字符串,会先检查有没有使用该字符串调用 Symbol.for 方法创建的 symbol 值。如果有,返回该值;如果没有,则使用该字符串新创建一个。使用该方法创建 symbol 值后会在全局范围进行注册。
上面代码中,创建了一个iframe节点并把它放在body中,通过这个 iframe 对象的 contentWindow 拿到这个 iframe 的 window 对象,在 iframe.contentWindow上添加一个值就相当于在当前页面定义一个全局变量一样。可以看到,在 iframe 中定义的键为 TypeScript 的 symbol 值在和在当前页面定义的键为'TypeScript'的symbol 值相等,说明它们是同一个值。
2)Symbol.keyFor() 该方法传入一个 symbol 值,返回该值在全局注册的键名:
看完简单的数据类型,下面就来看看比较复杂的数据类型,包括JavaScript中的数组和对象,以及TypeScript中新增的元组、枚举、Any、void、never、unknown。
在 TypeScript 中有两种定义数组的方式:
以上两种定义数组类型的方式虽然本质上没有任何区别,但是更推荐使用第一种形式来定义。一方面可以避免与 JSX 语法冲突,另一方面可以减少代码量。
注意,这两种写法中的 number 指定的是数组元素的类型,也可以在这里将数组的元素指定为其他任意类型。如果要指定一个数组里的元素既可以是数值也可以是字符串,那么可以使用这种方式: number|string[] 。
在JavaScript中,object是引用类型,它存储的是值的引用。在TypeScript中,当想让一个变量或者函数的参数的类型是一个对象的形式时,可以使用这个类型:
可以看到,当给一个对象类型的变量赋值一个对象时,就会报错。对象类型更适合以下场景:
在 JavaScript 中并没有元组的概念,作为一门动态类型语言,它的优势是支持多类型元素数组。但是出于较好的扩展性、可读性和稳定性考虑,我们通常会把不同类型的值通过键值对的形式塞到一个对象中,再返回这个对象,而不是使用没有任何限制的数组。TypeScript 的元组类型正好弥补了这个不足,使得定义包含固定个数元素、每个元素类型未必相同的数组成为可能。
元组可以看做是数组的扩展,它表示已知元素数量和类型的数组,它特别适合用来实现多值返回。确切的说,就是已知数组中每一个位置上的元素的类型,可以通过元组的索引为元素赋值::
可以看到,定义的arr元组中,元素个数和元素类型都是确定的,当为arr赋值时,各个位置上的元素类型都要对应,元素个数也要一致。
当访问元组元素时,TypeScript也会对元素做类型检查,如果元素是一个字符串,那么它只能使用字符串方法,如果使用别的类型的方法,就会报错。
在TypeScript 新的版本中,TypeScript会对元组做越界判断。超出规定个数的元素称作越界元素,元素赋值必须类型和个数都对应,不能超出定义的元素个数。
这里定义了接口 Tuple ,它继承数组类型,并且数组元素的类型是 number 和 string 构成的联合类型,这样接口 Tuple 就拥有了数组类型所有的特性。并且指定索引为0的值为 string 类型,索引为1的值为 number 类型,同时指定 length 属性的类型字面量为 2,这样在指定一个类型为这个接口 Tuple 时,这个值必须是数组,而且如果元素个数超过2个时,它的length就不是2是大于2的数了,就不满足这个接口定义了,所以就会报错;当然,如果元素个数不够2个也会报错,因为索引为0或1的值缺失。
TypeScript 在 ES 原有类型基础上加入枚举类型,使得在 TypeScript 中也可以给一组数值赋予名字,这样对开发者比较友好。枚举类型使用enum来定义:
上面定义的枚举类型的Roles,它有三个值,TypeScript会为它们每个值分配编号,默认从0开始,在使用时,就可以使用名字而不需要记数字和名称的对应关系了:
除此之外,还可以修改这个数值,让SUPER_ADMIN = 1,这样后面的值就分别是2和3。当然还可以给每个值赋予不同的、不按顺序排列的值:
我们可以将一个值定义为any类型,也可以在定义数组类型时使用any来指定数组中的元素类型为任意类型:
any 类型会在对象的调用链中进行传导,即any 类型对象的任意属性的类型都是 any,如下代码所示:
需要注意:不要滥用any类型,如果代码中充满了any,那TypeScript和JavaScript就毫无区别了,所以除非有充足的理由,否则应该尽量避免使用 any ,并且开启禁用隐式 any 的设置。
void 和 any 相反,any 是表示任意类型,而 void 是表示没有类型,就是什么类型都不是。这在 定义函数,并且函数没有返回值时会用到 :
需要注意: void 类型的变量只能赋值为 undefined 和 null ,其他类型不能赋值给 void 类型的变量。
never 类型指永远不存在值的类型,它是那些 总会抛出异常 或 根本不会有返回值的函数表达式的返回值 类型,当变量被永不为真的类型保护所约束时,该变量也是 never 类型。
下面的函数,总是会抛出异常,所以它的返回值类型是never,用来表明它的返回值是不存在的:
never 类型是任何类型的子类型,所以它可以赋值给任何类型;而没有类型是 never 的子类型,所以除了它自身以外,其他类型(包括 any 类型)都不能为 never 类型赋值。
上面代码定义了一个立即执行函数,函数体是一个死循环,这个函数调用后的返回值类型为 never,所以赋值之后 neverVariable 的类型是 never 类型,当给neverVariable 赋值 123 时,就会报错,因为除它自身外任何类型都不能赋值给 never 类型。
基于 never 的特性,我们可以把 never 作为接口类型下的属性类型,用来禁止操作接口下特定的属性:
可以看到,无论给 props.name 赋什么类型的值,它都会提示类型错误,这就相当于将 name 属性设置为了只读 。
unknown 是TypeScript在3.0版本新增的类型,主要用来描述类型并不确定的变量。它看起来和any很像,但是还是有区别的,unknown相对于any更安全。
对于any,来看一个例子:
上面这些语句都不会报错,因为value是any类型,所以后面三个操作都有合法的情况,当value是一个对象时,访问name属性是没问题的;当value是数值类型的时候,调用它的toFixed方法没问题;当value是字符串或数组时获取它的length属性是没问题的。
当指定值为unknown类型的时候,如果没有 缩小类型范围 的话,是不能对它进行任何操作的。总之,unknown类型的值不能随便操作。那什么是类型范围缩小呢?下面来看一个例子:
这里由于把value的类型缩小为Date实例的范围内,所以进行了value.toISOString(),也就是使用ISO标准将 Date 对象转换为字符串。
使用以下方式也可以缩小类型范围:
关于 unknown 类型,在使用时需要注意以下几点:
在实际使用中,如果有类型无法确定的情况,要尽量避免使用 any,因为 any 会丢失类型信息,一旦一个类型被指定为 any,那么在它上面进行任何操作都是合法的,所以会有意想不到的情况发生。因此如果遇到无法确定类型的情况,要先考虑使用 unknown。
【typescript数据结构】的内容来源于互联网,如引用不当,请联系我们修改。
网友留言: