TS学习笔记之类型系统

136 阅读6分钟

该系列文章是本人阅读阮一峰老师的《TypeScript教程》学习笔记,欢迎各位大佬指出不正确的地方,感谢!

基本类型

TS继承了JS的类型,在此基础上定义了一套自己的类型系统。

下面8个类型可以看作是TS的基本类型,复杂类型由它们组成。

所有类型名称都是小写字母,首字母大的Number、String、Boolean等在JS中都是内置对象,不是类型的名称。

undefined和null既是类型对象,也可作为类型名称,取决于在何处使用。

boolean

只包含true和false两个布尔值。

string

包含是有字符串。

number

包含所有整数和浮点数。

bigint

包含所有的大整数,且与number类型不兼容。

bigint是ES2020标准引入的,如果使用这个类型,TS编译目标JS版本不能低于ES2020。

symbol

包含所有的Symbol值。

object

根据JS的设计,object类型包含了所有对象、数组和函数。

undefined类型、null类型

undefined和null是两个独立类型,它们各自只有一个值。

undefined类型只包含一个值undefined,表示未定义(即还未给出定义,以后可能有定义)。

null类型只包含一个值null,表示为空(即此处没有值)。

如果没有类型声明的变量被赋值undefined或者是null,则类型会被推断为any。如果希望避免这种情况,则需要打开编译选项strictNullChecks。打开这个选项,undefined和null就不能赋值给其他类型的变量(除了any类型和unknown类型)。

image.png

image.png

特殊性

任何其他类型的边炉昂都可以赋值为undefined或null,这并不是因为undefined和null包含在其他类型里面,而是故意这样设计,以便跟JS保持一致性。

包装对象的概念

JS的8种类型,undefined和null是两个特殊的值,object属于复合类型,剩下的5个类型属于原始类型,代表着最基本、不可再分的值。

原始类型都有对应的包装对象(这些值在需要时,会自动产生的对象)。

5种包装对象中,symbol类型和bigint类型无法直接获取它们的包装对象(即Symbol()和BigInt()不能作为构造函数使用,因此Symbol和BigInt这两个类型虽然存在,但完全没有使用的理由)。

举个例子:String()只有当作构造函数使用时(即带有new命令调用),才会返回包装对象。如果当作普通函数使用(不带new命令),返回就是一个普通字符串。其它两个构造函数Number()和Boolean()也是如此。

包装对象类型与字面量类型

由于包装对象的存在,导致每个原始类型的值都有包装对象(带new的)和字面量('hello')两种情况。

为了区分这两种情况,TS对5种原始类型分别提供了大写(同时包含包装对象和字面量)和小写两种类型(不包含包装对象)。

建议只使用小写类型,不使用大写类型。因为大部分使用原始类型的场合,都是使用字面量,不使用包装对象。而且,TS把很多内置方法的参数,定义成小写类型,使用大写类型会报错(比如说Math方法)。

Object类型与object类型

Object类型

大写的Object类型代表JS语言里面的广义对象(除了undefined和null不能转为对象)。所有可以转成对象的值,都是Object类型,这囊括了几乎所有的值。

空对象{}是Object类型的简写形式,但所有不包的Object类型既不符合直觉,也不方便使用。

object类型

小写的object类型代表JS里面的狭义对象,即可用字面量表示的对象,只包含对象、数组和函数,不包括原始类型的值。

不论是大写的Object类型还是小写的object类型,都只包含JS内置对象原生的属性和方法,用户自定义的属性和方法都不存在于这两个类型之中,访问会报错。

值类型

TS规定单个值也是一种类型,称为“值类型”。

TS推断类型时,遇到const声明的变量,如果代码里面没有注明类型,就会推断该变量为值类型。如果赋值为对象,并不会推断为值类型。

在TS中,子类型能赋值给父类型,父类型不能赋值给子类型,如果一定要子类型可以被赋值为父类型的值,就要用上类型断言(as)。

联合类型

联合类型是指多个类型组合成的一个新的类型,使用符号|表示。

联合类型可以与值类型结合,表示一个变量的值有若干种可能,即使配置了strictNullChecks,只要联合类型中有 undefined或null,都能赋值undefined或null。

联合类型的第一个成员前面也可以加上|,这样便于多行书写。

image.png 如果一个变量有多种类型,读取该变量时,往往需要进行“变量缩小”,区分该值到底为哪一种类型,然后再进一步处理。联合类型可以看成是一种“类型放大”,处理时就需要进行“类型缩小”。

交叉类型

交叉类型指多个类型组成的一个新的类型,使用符号&表示。

交叉类型A&B表示任何一个类型必须同时属于A和B,才属于交叉类型A&B,即交叉类型同时满足A和B的特征。

image.png 交叉类型的主要用途是表示对象的合成。

image.png 或者是为对象类型添加新属性。

image.png

type命令

type用来定义一个类型的别名。

image.png 别名不可重复。

别名的作用域是块级作用域。

别名支持使用表达式,也可以在定义一个别名时,使用另外一个别名,即别名允许嵌套。

image.png

typeof运算符

JS中,typeof是一个一元运算符,返回一个字符串,代表操作数的类型。

image.png JS里面,typeof只可能返回8种结果,而且都是字符串。

image.png TS将typeof运算符移植到了类型运算,它的操作数依然是一个值,但返回的不是字符串而是该值的TS类型。

image.png 同一段代码可能存在两种typeof运算符,一种用在值相关的JS代码中,另一种用在类型相关的TS代码部分。

image.png 由于编译时不会进行JS代码的运算,所以TS规定,typeof的参数只能是标识符,不能是需要运算的表达式。

image.png typeof的参数不能是类型。

image.png

块级类型声明

TS支持块级类型声明,即类型可以声明在代码块(用大括号表示)里面,并且只在当前代码块有效。

类型兼容

TS的类型存在类型兼容,某些类型可以兼容其他类型。

image.png 如果类型A的值可以赋值给类型B,那么类型A就称为类型B的子类型。TS的一个规则是,凡是可以用父类型的地方,都可以使用子类型,但反过来不行。

image.png 因为子类型继承了父类型的所有特征,所以可以用在父类型的场合。但是子类型可能有一些父类型没有的特征,所以父类型不能用在子类型的场合。