该系列文章是本人阅读阮一峰老师的《TypeScript教程》学习笔记,欢迎各位大佬指出不正确的地方,感谢!
简介
除了原始类型,对象是JS最基本的数据结构,TS对于对象类型有很多规则。
对象类型的最简单声明方法,就是使用大括号表示对象,在大括号内部声明每个属性和方法的类型。
属性的类型可以用分号结尾,也可以用逗号结尾。
一旦声明了类型,对象赋值时,就不能缺少指定的属性,也不能有多余的属性,读写不存在的属性也会报错,删除类型声明中存在的属性也会报错,但是可以修改它的值。
对象的方法使用函数类型描述。
对象类型可以使用方括号读取属性的类型。
除了type命令可以为对象类型声明一个别名,TS还提供了interface命令,可以把对象类型提炼为一个接口。
注意,TS不区分对象自身的属性和继承的属性,一律视为对象的属性。
可选属性
如果某个属性是可选的(即可忽略),需要在属性名后面加一个问号。
可选属性等同于允许赋值为undefined,下面两种方法是等效的。
所以读取一个可选属性的时候,可能得到undefined,在读取之前必须检查一下是否为undefined。
只读属性
属性名前面加还是那个readonly关键字,表示这个属性是只读属性,不能修改。
只读属性只能在对象初始化期间赋值,此后就不能修改该属性。
注意,如果属性值是一个对象,readonly修饰符并不禁止修改该对象的属性,只是禁止完全替换掉该对象。
如果一个对象有两个引用,即两个变量对应一个对象,其中一个变量是可写的,另一个变量是只读的,那么从可写变量修改属性,会影响到只读变量。
如果希望属性值是只读的,除了声明时加上readonly关键字,也可以在赋值时在对象后面加上只读断言as const。
as const属于TS的类型推断,如果变量明确地声明了类型,那么TS会以声明的类型为准。
属性名的索引类型
因为对象的属性非常多,有时候对象属性的数量也无法判断,所以TS允许采用属性名表达式的写法来描述类型,称为“属性名的索引类型”。
索引类型里面最常见的就是属性名的字符串索引。
JS对象的属性名的类型有三种可能:string、number和symbol。
对象可以同时有多种类型的属性名索引,比如同时拥有数值索引和字符串索引。但数值索引不能与字符串索引发生冲突,必须服从后者,因为在JS中,所有的数值属性名都会自动转为字符串属性名。
同样的,可以既声明属性名索引,也声明具体的单个属性名。如果单个属性名符合属性名索引的范围,两者不能有冲突,否则报错。
建议谨慎使用属性的索引类型写法,因为属性名的声明太宽泛了,约束太少。
另外,属性名的数值索引不宜用来声明数组,因为采用这种方式声明数组,就不能使用各种数组方法以及length属性,因为类型里面没有定义这些东西。
解构赋值
结构赋值用于直接从对象中提取属性。
解构赋值的类型写法,跟为对象声明类型是一样的。
注意,目前没法为结构变量指定类型,因为对象结构里面的冒号,JS指定了其它的用途。
这里要特别注意。
结构类型原则
只要对象B满足对象A的结构特征,TS就认为对象B兼容对象A的类型,这称为“结构类型”原则。
根据“结构类型”原则,TS检查某个值是否符合指定类型时,并不是检查这个值的类型名(即“名义类型”),而是检查这个值的结构是否符合要求(即“结构类型”)。
TS这样设计是为了符合JS的行为。JS并不关心对象是否严格相似,只要某个对象具有所要求的属性,就可以正确运行。
如果类型B可以赋值给类型A,TS就认为B是A的子类型,A是B的父类型。子类型满足服类型的所有结构特征,同时还具有自己的特征。凡是可以使用父类型的地方,都可以使用子类型,即子类型兼容父类型。
严格字面量检查
如果对象使用字面量表示,会触发TS的严格字面量检查。如果字面量的结构跟类型定义的不一样(比如多出了未定义的属性),就会报错。
如果等号右边不是字面量,而是一个变量,根据结构类型原则,是不会报错的。
TS对字面量进行严格检查的目的,主要是防止拼写错误。
规避严格字面量检查,可以使用中间变量。
如果确认字面量没有错误,也可以使用类型断言规避严格字面量检查。
如果允许字面量有多余属性,可以像下面这样在类型里面定义一个通用属性。
编译器选项suppressExcessPropertyErrors可以关闭多余属性检查。
最小可选属性规则
如果一个对象的所有属性都是可选的,会触发最小可选属性规则。
即使使用中间量赋值也无法规避规则。
空对象
空对象是TS的一种特殊值,也是一种特殊类型。
空对象只能使用继承属性,即继承自原型对象Object.prototype的属性。
先声明一个空对象再向空对象添加属性,是JS常见的写法。但是,TS不允许动态添加属性,所以对象不能分步生成,必须生成时一次性声明所有属性。
如果确实需要分布声明,一个比较好的方法是,使用扩展运算符(...)合成一个新的对象。
空对象作为类型,其实是Object类型的简写形式。
因为Object可以接受各种类型的值,而空对象是Object类型的简写,所以它不会有严格字面量检查,赋值时总允许多余的属性,只是不能读取这些属性。
如果想强制使用没有任何属性的对象,可以采用下面的写法: