该系列文章是本人阅读阮一峰老师的《TypeScript教程》学习笔记,欢迎各位大佬指出不正确的地方,感谢!
简介
interface是对象的模版,可以看作是一种类型约定。使用了某个模版的对象,就拥有了制定的类型结构。
方括号运算符可以取出interface某个属性的类型。
interface表示对象5种形式的语法
概括起来就是:对象属性、对象的属性索引、对象方法、函数、构造函数。
对象属性
属性之间用分号或者是逗号隔开,最后一个属性结尾的分号或逗号可以省略。
可选属性就在属性名后面加一个问号。
只读属性需要加上readonly修饰符。
对象的属性索引
属性索引共有string、number和symbol三种类型。
一个接口中,最多只能定义一个字符串索引。字符串索引会约束该类型中所有名字为字符串的属性。
属性的数值索引,其实是指定数组的类型。
一个接口中最多只能定义一个数值索引。数值索引会约束所有名称为数值的属性。
如果一个interface中同时定义了字符串索引和数值索引,那么数值索引必须服从于字符串索引。因为在JS中,数值属性名最终是自动转换成字符串属性名。
对象方法
对象的方法有三种写法:
属性名可以采用表达式,所以下面的写法也可以:
类型方法可以重载:
interface里面的函数重载不需要给出实现。但由于对象内部定义方法时,无法使用函数重载的语法,所以需要额外在对象外部给出函数方法的实现。
函数
interface也可以用来声明独立的函数。
构造函数
interface内部可以使用new关键字,表示构造函数。
TS里面,构造函数特指具有constructor属性的类。
interface的继承
interface可以继承其它类型。
interface继承interface
interface使用extends关键字(extends关键字会从继承的接口里面拷贝属性的类型,这样就不必书写重复的属性),继承其他interface。使用继承的是子接口,被继承的是父接口。
interface允许多重继承,相当于多个父接口的合并。
如果子接口与父接口存在同名属性,那么子接口的属性会覆盖父接口的属性。注意,子接口于父接口的同名属性必须是类型兼容的,不能有冲突,否则会报错。
多重继承时,如果多个父接口存在同名属性,那么这些同名属性不能有类型冲突,否则会报错。
interface继承type
interface可以继承type命令定义的对象类型,type命令定义的类型不是对象则无法继承。
interface继承class
interface继承class即继承该类的所有成员。
某些类拥有私有成员和保护成员,interface可以继续继承这样的类,但意义不大。
接口合并
多个同名接口会合并成一个接口。
这样的设计主要是为了兼容JS的行为。JS开发者常常对全局对象或者外部库添加自己的属性和方法。那么,只要使用interface给出这些自定义属性和方法的类型,就能自动跟原始的interface合并,使得扩展外部类型非常方便。
同名接口合并时,同一属性如果有多个类型声明,彼此不能有类型冲突。
同名接口合并时,如果同名方法有不同的类型声明,那么会发生函数重载。而且,后面的定义比前面的定义具有更高的优先级。
这个规则有一个例外:同名方法中,如果有一个参数是字面量类型,字面量类型有更高的优先级。
一个实际的例子是Document对象的createElement()方法,它会根据参数的不同而生成不同的HTML节点对象。
如果两个interface组成的联合类型存在同名属性,那么该属性的类型也是联合类型。
interface与type的异同
相同点
- 定义对象类型
两者均可描述对象的形状(属性及类型);
- 支持扩展
interface通过extends继承其它接口,type通过交叉类型(&)合并类型。
- 类型检查行为一致 在大多数场景下,两者对类型的约束效果相同。
不同点
interface不能包含属性映射(mapping),type可以。
this关键字只能用于interface。
type可以扩展原始数据类型,interface不行。
interface无法表达某些复杂类型(比如交叉类型和联合类型),但type可以。
使用建议
- 优先用interface
描述对象、函数或类的形状;
需要利用声明合并特性(如第三方库扩展类型)。
- 优先用type
定义联合类型、元组或基本类型别名;
需要更复杂的类型组合逻辑。