1. TS基本特性
1.1 静态类型检查
在代码运行之前检查 值 应有的结构和行为
1.2 非异常失败
非异常失败是指一些语法错误的提示,主要包含如下几种
- 对象属性不存在的时候调用
- 拼写错误
- 函数未被调用
- 基本逻辑错误
1.2.1 对象属性不存在的时候调用
1.2.2 拼写错误
1.2.3 函数未被调用
1.2.4 基本逻辑错误
1.3 类型工具
使用
typeScript
的时候,会自动给我们提供如下功能
- 获取变量属性:ts会根据变量类型自动给出相应属性的使用提示
- 代码补齐
- 快速修复功能
1.4 tsc: TypeScript编译器
安装:
npm i -g typescript
编译:
tsc fileName
- 编译之后会自动在同级目录生成一个同文件名的js文件
- 如果编译过程中有报错,会在控制台提示出来
1.5 报错不产生编译文件
在上面例子中,即使使用
tsc
编译报错,编译后的文件依然会生成有时候如果需要更严格的控制,可以在编译命令中增加
--noEmitOnError
命令来禁止报错时编译文件的生成
禁止编译报错生成文件:tsc --noEmitOnError filename
1.6 ES编译降级
使用
tsc
命令编译ts
的时候,默认会被编译成 ES3(EcmaScript比较老的一个版本) 语法的 js,我们可以使用target
命令将其编译成一些比较新的版本
编译成ES5:tsc --target es2015 filename
1.7 严格模式
如果你希望
ts
尽可能多的检查代码,可以通过开启如下配置,使用更严格的检查模式
1.7.1 规避any
noImplicitAny
: 当类型被隐形推断为 any
的时候会报错
1.7.2 规避 null,undefined
strictNullChecks
:该配置让我们更明确的处理 null
和 undefined
,避免忘记处理 null
和 undefined
从而导致的bug
2. 常见类型
2.1 原始类型
typeScript中原始类型有三种:string, number, boolean
2.2 数组
常见数组有 数字数组和 字符串数组
2.3 any
在ts中,
any
是一种特殊的类型,当你不希望编译器对变量的值进行检查的时候,可以使用any
(相当于js变量)一般不推荐使用
any
,除非是刻意不希望编译器检查变量的时候,默认情况下编译器会根据变量值去推断变量类型,从而给出相应的检查和提示
2.4 函数
函数主要有两种类型的注解
参数类型注解
当参数有了类型注解之后,Ts便会检查函数的实参
即使没有添加参数类型注解,Ts依然会检查传入的参数数量是否正确
返回值类型注解
- 返回值类型注解(非必要,TS会根据
return
语句推断函数的返回值类型)
2.5 对象
- 定义一个对象类型,需要简单的列出它的属性和对应类型
function greet(obj: { name: string; age: number }){}
greet({name: 'kobe', age: 18})
对象类型可选属性
对象类型可以指定属性为可选的,只需要在属性名后面增加一个?
在使用一个可选属性之前,需要检查一下是否为undefined
2.6 联合类型
2.6.1 定义联合类型
联合类型: 由两个或更多个基础类型组成的组合, 表示值可以是其中的任意一种类型
2.6.2 使用联合类型
Ts要求你使用联合类型的时候,需要对每一个可能的类型都是有效的,例如有一个
number | string
类型的变量,你不能使用只存在string
类型变量上面的方法
- 类型收窄:针对每种可能类型做判断,单该类型存在,再使用
- 使用共用属性:每一种可能类型都存在的属性可以直接用
引用 mqyqingfeng 大佬的一个解释:你可能很奇怪,为什么联合类型只能使用这些类型属性的交集,让我们举个例子,现在有两个房间,一个房间都是身高八尺戴帽子的人,另外一个房间则是会讲西班牙语戴帽子的人,合并这两个房间后,我们唯一知道的事情是:每一个人都戴着帽子。
2.7 类型别名
有时候,当一种类型被多次引用的时候,我们希望通过一个单独的名字去使用它,这时候类型别名就出现了
类型别名:一个可以指代任意类型的名字
2.8 接口
接口和类型别名相似,大部分时候可以任意使用。
两者的关键区别在于接口可以扩展,但是类型别名无法添加新的属性
2.9 类型别名和接口的区别
- 类型别名不可重复声明,但是接口可以,重复声明的接口将会合并(不能覆盖前面声明的类型)
- 类型别名只能通过交集去扩展类型,但是接口可以通过继承去扩展类型
- 报错信息中,接口名一定会出现,而类型名是有可能会出现
2.10 字面量类型
除了常见的 string
和 number
类型之外,我们还可以声明更为具体的数字和字符串类型
即该值只能是指定的字面量类型之一,否则报错
2.11 null 和 undefined
在 javascript
中,有两个原始类型的值用来表示值为 空 或者 未初始化,他们分别是 null
和 undefined
在 TypeScript 中也同样对应这两个类型,但是他们的行为取决于是否开启了strictNullChecks
配置
strictNullChecks关闭
strickNullChecks
关闭的时候,如果一个值是 Null
或者 undefined
,它们任可以被正常的访问,或者赋值给任意类型的属性,但是这种检查的缺少,正是导致bug的主要源头,所以始终推荐开发者开启 strictNullChecks
选项
strictNullChecks开启
当 strictNullChecks
选项开启的时候,如果一个值是 null
或 undefined
,使用它之前需要先检查一下是否为 undefined
2.12 非空类型断言
TypeScript 提供一个特殊的语法,在不做检查的情况下,从类型中移除 null
和 undefined
这就是在任意类型后面加上!,表示这是一个非空类型的断言,表示它的值不可能是 null
或 undefined
注意:当你明确知道这个值不可能是 null
或 undefined
的时候才使用 !
总结
- 相对于 JS 来说,TS 给开发者提供了更为严格的静态类型检查,更智能的类型提示工具,更好的异常失败提醒
- 所有的
.ts
文件最终都会被编译成.js
文件,我们可以通过 TypeScript 编译器手动编译某个.ts
文件 tsc --noEmitOnError filename
命令可以用来预防编译报错文件的生成- Ts 常见类型有
number
,string
,boolean
,数组
,对象
,any
这几种, - 字面量类型可以指定具体的值作为某个变量的取值,联合类型可以通过
|
的方式将集中不通类型的取值指定到同一个变量上面 - 建议始终在项目中开启
strictNullChecks
,使用null
和undefined
之前进行类型收窄的判定
3.类型收窄
3.1 类型收窄概念
在前面我们介绍联合类型的时候提到过 类型收窄 这个概念
简单来讲就是 当一个值可能拥有多种类型的时候,我们需要使用一定的类型判断,将它推导为更精确类型的这个过程,我们称之为收窄
因为在 TS 中,每一个值使用的时候,编译器都需要知道它确定的值类型
错误示范
如果你能一眼就看出问题,那说明联合类型那里你学的不错,如果你看不出来,也没关系,我们一起再回顾一下
使用联合类型的时候,你不能只使用存在某一个类型上面的方法,如果你不愿意做 类型收窄,那么你就只能使用所有可能类型都存在的公用方法 例: 现有
const id = number | string
如果不通过某些类型判断方法去确定 id 具体类型,那么我们就只能使用
string
和number
都存在的方法或属性
正确示范
3.2 类型保护
类型保护用一句话说就是:在使用某个不确定类型的值之前,对该类型做一定的判断,确定是该类型的时候才去使用
最常用的类型保护方法是:typeof
- string
- number
- bigInt
- boolean
- symbol
- undefined
- object
- function
⚠️注意:typeof只能准确检验出基本数据类型
3.3 类型收窄的方式
3.3.1 真值收窄
通俗来说就是在条件语句 if
中使用任何表达式,例如用逻辑运算符 &&
, ||
, !
来判断是否是某个特定类型
示例1
示例2
示例3
3.3.2 等值收窄
通过 switch
语句或 ===
, !==
, ==
, !=
去收窄类型
示例1
示例2
⚠️注意:当使用 someValue != null
来判断的时候,null
和 undefined
都返回 true
3.3.3 in操作符
在 JavaScript 中,in
操作符可以用来判断某个对象是否拥有某个属性名,Ts 也可以通过这个收窄类型
3.3.4 instanceof收窄
前面我们说过,typeof 可以用来收窄基本数据类型,那么相对的, instanceof
用来收窄引用数据类型
3.3.5 赋值语句收窄
Ts 可以根据赋值语句右边的值,正确收窄左侧的变量类型
3.4 控制流分析
前面介绍了 TS 中一些基础的类型收窄用法,现在我们来看下在实际的逻辑语句中类型保护的例子
概念
TS 通过代码分析,在过滤掉前面的类型收窄之后,剩余的部分就会从 原可能的类型中删掉,所以到逻辑的最后,遗留的值就是未做明确类型收窄的值类型。这种基于 可达性 的代码分析就叫做控制流分析
3.5 类型判断式
类型判断式是用来是我们的类型收窄更加灵活方便的,通过类型判断式我们可以自定义一个类型保护
语法:parameterName is Type
使用示例
3.6 可辨别联合
可辨别联合,通俗理解就是 在某个联合类型中,可以通过特定的共有属性或方法,来达到识别某种类型的目的
3.7 never类型
never定义
TS 中有一个
never
类型用来表示一个不可能存在的值never 类型可以赋值给任何类型,但是,没有任何类型可以赋值给 never(除了never自身)
3.8 穷尽检查
穷尽检查的概念: 当我们想通过类型收窄判断所有的类型,但是又担心遗漏的时候,可以通过 never
做一个类型穷尽检查,因为任何类型都不能被赋值给 never
,这时候就会产生一个编译错误,以达到提示开发者的目的
总结
总得来说,这一章主要介绍了 TS类型收窄的基本概念,以及在类型收窄的基础上我们可以去使用的类型保护方法,所有的类型方法都是源于 JS 的基础类型判定语法,主要有
- 真值收窄(逻辑运算)
- 等值收窄(
===
,!==
,==
,!=
) - in 操作符 结合联合类型使用 ('protoName' in Obj)
- Instanceof收窄(判定引用类型)
- 赋值收窄 (通过复制语句限定变量类型)
这几种类型收窄的方法,在实际实践过程中可根据具体情况结合使用
其次,通过控制流分析,在某些场景下可以自动分析出变量的类型,不用我们主动对所有类型做收窄的判断
还有类型判断式 可以方便我们自定义类型保护的方法,可辨别联合 算不上一种特殊的方法,在我看来更多的像是组合代码逻辑的一种技巧,最后我们学习了一个 never 类型,主要用来做穷尽检查的,特别是在我们在 switch
中无法详细的陈列出所有的类型的时候。最后的最后记住never的特性:只能赋值给其它,不能被除 never
之外的任何类型赋值
🎉这篇就到这里了,小伙伴们,我们下期再见吧
👉下期预告:【函数,对象类型,泛型】
更多学习笔记和优质内容,请关注公众号:马小飞学前端