TypeScript入门教程(一)
TypeScript学习
TypeScript 的发展已经深入到前端社区的方方面面了,任何规模的项目都或多或少得到了 TypeScript 的支持。同时vue3在经过vue2之后的发展过程中采用了TypeScript进行了重构,也让使用vue作为主力开发框架的开发者们,需要学习TypeScript来适应日常的开发过程。
同时也有赖于TypeScript这门语言的优点:
- 完全兼容于JavaScript
- 适用于任何规模
使得我们的开发的代码能够更加严谨和健壮!
学习内容及教程推荐
- TypeScript入门教程 中文文档,很容易阅读和理解,对于新手十分友好
- typescript中文官网–手书 英文文档,阅读体验对国人不是很友好
- typescript中文文档教程 当前最新typescript版本为 “typescript”: “^4.3.2”,文档最新版本只更新到v3.1版本,是有滞后的。
除了实现 ECMAScript 标准之外,TypeScript 团队也推进了诸多语法提案
可选链操作符(?.)
参考链接: https://zh.javascript.info/optional-chaining
空值合并操作符
参考链接: https://zh.javascript.info/nullish-coalescing-operator
throw表达式
throw 语句抛出一个错误。
当错误发生时, JavaScript 会停止执行并抛出错误信息。
描述这种情况的技术术语是:JavaScript 将抛出一个错误。
throw 语句创建自定义错误。
技术术语是: 抛出异常。
异常可以是 JavaScript 字符串、数字、逻辑值或对象:
正则匹配索引
typescript的安装
使用命令行工具
1 |
|
hello.ts
1.新建一个简单函数:hello.ts
1 |
|
2.安装好typescript后,在命令行终端键入以下命令: tsc hello.ts
即可看到显示的hello.js文件
TypeScript 只会在编译时对类型进行静态检查,如果发现有错误,编译的时候就会报错。而在运行时,与普通的 JavaScript 文件一样,不会对类型进行检查。
简单来说,typescript主要是在编译过程中检查错误的存在,在没有进行其他设置的情况下,即使错误,也会继续生成相应的js文件,当然这对于使用typescript的用户来说是需要避免的,开发着需要在ts编译阶段报错时终止(ts文件→js文件)这一过程,需要进行以下配置
可以在 tsconfig.json 中配置 noEmitOnError 即可。关于 tsconfig.json,参考思否教程。
typescript基础
原始数据类型
原始数据类型现今总共有: 7种 = 5种 + 2种
5种: 布尔值,数值,字符串,null, undefined
2种: Symbol (ES6新类型); BigInt(ES10新类型)
布尔值
1 |
|
很明显可以正常编译,那么采用构造函数的形式呢?
1 |
|
error TS2322: Type ‘Boolean’ is not assignable to type ‘boolean’.
‘boolean’ is a primitive, but ‘Boolean’ is a wrapper object. Prefer using ‘boolean’ when possible.
Boolean 是对应布尔值的引用类型。要创建一个 Boolean 对象,就使用 Boolean 构造函数并传入
true 或 false
即通过构造函数new Boolean(1)的结果实际是布尔值对象,而不是布尔值,所以会出现类型错误,理解原始布尔值和 Boolean 对象之间的区别非常重要,强烈建议永远不要使用后者.
1 |
|
数字
1 |
|
void \ null \ undfined
在typescript中没有空值的概念,遇到这种情况可以采用void来标识没有返回值的函数 (划重点:没有返回值的函数)
1 |
|
声明一个void类型的变量是没有什么用处的,因为之后你只能将它赋值为null或者undfined(只在 --strictNullChecks 未指定时):
注意是变量,对于没有返回值的函数还是有必要的
undefined 和 null 两个空类型的设计,使用上不方便,所以 通过strictNullChecks严格校验类型,让代码更安全
1 |
|
注意:
1.与 void 的区别是,undefined 和 null 是所有类型的子类型。也就是说 undefined 类型的变量,可以赋值给 number 类型的变量:
2.而 void 类型的变量不能赋值给 number 类型的变量:
any
如果是一个普通类型,在赋值过程中改变类型是不被允许的:但如果是 any 类型,则允许被赋值为任意类型。在任意值上访问任何属性都是允许的:也允许调用任何方法:变量如果在声明的时候,未指定其类型,那么它会被识别为任意值类型
类型推论
- 类型推论: 字面意思即使,当类型没有被明确指定的时候,那么 TypeScript 会依照类* 型推论(Type Inference)的规则推断出一个类型。
- 如果定义的时候没有赋值,不管之后有没有赋值,都会被推断成 any 类型而完全不被类型检查。
联合类型
- 即在定义类型时可以拥有多种类型,联合类型使用 | 分隔每个类型。
- 当 TypeScript 不确定一个联合类型的变量到底是哪个类型的时候,我们只能访问此联合类型的所有类型里共有的属性或方法:
1 |
|
当访问的不是共有属性或者方法的时候,就会报错。联合类型的变量在被赋值的时候,会根据类型推论的规则推断出一个类型:
1 |
|
上例中,第二行的 myFavoriteNumber 被推断成了 string,访问它的 length 属性不会报错。而第四行的 myFavoriteNumber 被推断成了 number,访问它的 length 属性时就报错了。
接口 (给对象准备的自定义类型)
实例代码:
1 |
|
形状得一样
赋值的时候需要保证接口的形状必须和其指定的类型一样。
可选属性(形状可以不一样,得加条件)
当然在开发需求中也会有需要其中某一个或者某几个,不要限制的那么死板,于是就有了 可选属性,通过在“:”前添加一个“?”来表示属性的可选性,这样也可以使得限制变得宽松,形状也可以有不一致。
可选属性可以实现已定义属性的有或无,但是对于未定义的属性,则产生了限制,因为它有严格的形状限制,而有时候我们希望一个接口允许有任意的属性,可以使用如下方式:
1 |
|
一旦定义了任意属性,那么确定属性和可选属性的类型都必须是它的类型的子集:
在上面的例子中,我们将任意属性的类型指定为any,则name指定的字符串类型和age指定的数字类型都是any类型的子集,所以是符合要求的。
下面来测试一个不属于其子集的例子:
1 |
|
只读属性(readonly)
在一些情况下,我们需要值是只读属性,当它被赋值一次以后,不能再对其进行赋值,此时可以采用readonly属性来指定。
1 |
|
使用readonly属性的时候,需要在定义的时候即赋值,在其拥有readonly属性之后再通过对象操作的方式进行赋值也会报错。
1 |
|
数组类型
数组是日常开发中遇到的最多的数据结构之一,从它的基本方法的多样性也可以看出它的使用度是极高的。那么在typescript世界中对于数组类型的定义又会有哪些实用方式呢?
类型+方括号 表示法
数组字面量是非常普遍的数组定义方法,在typescript中则采用了 类型+方括号的组成,一方面能够非常方便得表示数组,另一方面可以限制数组内元素得类型。
1 |
|
1.数组的项中不允许出现其他的类型,且数组的一些方法也会根据数组在定义时候的类型加以限制。
1 |
|
1 |
|
定义一个任意类型的数组:
1 |
|
泛型
我们也可以使用数组泛型(Array Generic) Array<类型> 来表示数组:
1 |
|
用接口表示数组
1 |
|
结合数组的特点,首先索引值必须是数字,在上述的例子中规定了属性值也为数字,所以可以将[1,1,2,3,5]赋值给fibonacci.
与前两种比较而言,此种方法是比较复杂的,当然它的主要用处是用来表示类数组。
类数组
类数组的概念
想要理解为什么多用比较复杂的接口来定义类数组? 首先需要了解类数组的基本概念。
类数组不是数组,它的原型是对象
1 |
|
事实上常用的类数组都有自己的接口定义,如 IArguments, NodeList, HTMLCollection 等:
1 |
|
其中 IArguments 是 TypeScript 中定义好了的类型,它实际上就是:内置对象
1 |
|
函数的类型
前面提到过可以用void来表示没有返回值的函数类型,这一节,我们将学习到对于有返回值的函数应该怎么表示,函数作为编程语言里不可缺少的部分,能够利用其灵活性,给我们的代码开发过程中带来效率的提升。首先,需要重温一下原生JavaScript中对于函数的声明方式:函数声明(Function Declaration)和函数表达式(Function Expression):
1 |
|
一个函数有输入和输出,要在typescript中对其进行约束,需要把输入和输出都考虑到
1 |
|
注意:输入多余的(或者少于要求的)参数,是不被允许的:
- 多输入参数:
1
2
3
4
5
6function sum(x: number, y: number): number {
return x + y;
}
sum(1, 2, 3);
// index.ts(4,1): error TS2346: Supplied parameters do not match any signature of call target. - 少输入参数:
1
2
3
4
5
6function sum(x: number, y: number): number {
return x + y;
}
sum(1);
// index.ts(4,1): error TS2346: Supplied parameters do not match any signature of call target.
函数表达式的类型加注
函数表达式相较于函数声明式是比较复杂的,首先是因为在赋值表达式两边都有字符,实际上如果在函数表达式左侧不对类型加以约束,在编译过程是可以通过的。 为了严谨,需要在函数左侧也加以类型约束。 通过类似于ES6中的箭头函数的样式,来表示函数左侧的样式,当然其本质还是不同的,在 TypeScript 的类型定义中,=> 用来表示函数的定义,左边是输入类型,需要用括号括起来,右边是输出类型。
1 |
|
当然为了代码的可读性,也可以采用接口的方式定义函数
1 |
|
难点:用接口定义函数的理解
怎么理解用typescript接口定义函数
typescript定义函数类型
个人理解:在定义接口的时候,因为是应用于函数的接口定义,所以左侧是函数的参数类型,通过冒号连接右侧的,实际是表示函数的类型的值,相当于用 “=>” 在函数表达式中的实现方式,应该是一种约定的方式。
前文提到:在没有使用可选参数的情况下,对于函数而言,在输入端多输入参数或者是少输入参数都会产生错误,在使用可选参数时,可以放松一些对于函数输入的要求,但是也有限制。
1 |
|
可选参数后面不允许再出现必需参数了:
1 |
|
参数默认值
在ES6中允许给函数的参数设置默认值,在typescript会将具有默认值的参数识别为可选参数,
1 |
|
此时就不受「可选参数必须接在必需参数后面」的限制了:
1 |
|
剩余参数
剩余参数,rest后面不能再有其他参数了,表示除了之前的参数外的其余的所有参数。ES6-剩余参数
1 |
|
它定义了一个push函数,能将其参数加入到一个数组中。
重载
对于文章中的重载不是很理解,因为JavaScript是没有重载这一概念的,
1 |
|