typescript的核心原则之一是对值所具有的结构进行类型检查。它有时被称作 “结构性子类型化”。在typescript里,接口的作用就是为这些类型命名和为你的代码或第三方代码定义契约
1、接口初探
类型检查器不会检查属性的顺序,只要相应的属性存在并且类型也是对的就可以
2、可选属性
接口的属性不全部都是必须的,有些只在某些条件不存在,或者根本不存在。可选属性在应用“option bags”模式时很常用,即给函数传入的参数对象中只有部分属性赋值了
如果接口中的属性指定是必选,则若是此接口类型指定的参数不传该属性,会报错
带有可选属性的接口与普通的接口定义差不多,只是在可选属性名字定义的后面加一个?符号
可选属性的好处之一是可以对可能存在的属性进行预定义,好处之二是可以捕获引用了不存在的属性时的错误
3、只读属性
一些对象属性只能在对象刚刚创建的时候修改其值。你可以在属性名前用readonly来指定只读属性
即使把整个ReadonlyArray赋值到一个普通数组也是不可以的。但是你可以用类型断言重写
最简单判断该用readonly还是const的方法是要看把它作为变量使用还是作为一个属性。做为变量使用的话用const,若作为属性则用readonly
4、额外的属性检查
当函数传入的参数中含有接口中未定义的属性,将会报错
绕开这种检查,可以使用类型断言
或者 创建一个对象变量,将对象作为参数传递 --因为zdObj不会经过额外的属性检查,所以编译器不会报错
然而最佳的方式是能够添加一个字符串索引签名,前提是你能够确定这个对象可能具有某些作为特殊用途使用的额外属性。
propName 是参数
5、函数类型
接口能够描述javascript中对象拥有的各种各样的外形。除了描述带有属性的普通对象外,接口也可以描述函数类型
为了使用接口表示函数类型,我们需要给接口定义一个调用签名。他就像是一个只有参数列表和返回值类型的函数定义。参数列表里的每个参数都需要名字和类型
对于函数类型的类型检查来说,函数的参数名不需要与接口里定义的名字相匹配 ,函数的参数会逐个进行检查,要求对应位置上的参数类型都是兼容的 。 也可以忽略参数类型,因为typescript系统会推断出参数类型
因为函数直接赋值给了SearchFunc类型变量。函数的返回值类型是通过其返回值推断出来的(此例是true/false)。如果让这个函数返回数字或者字符串,类型检查器会警告我们函数的返回值类型与SearchFunc接口中的定义不匹配
使用类继承其接口
6、可索引的类型
与使用接口描述函数类型差不多,我们也可以描述那些能够“通过索引得到的类型”,比如: a[10]或ageMap["daniel"]。
可索引类型具有一个索引签名,它描述了对象索引的类型,还有相应的索引返回值类型
TypeScript支持两种索引签名:字符串和数字。可以同时使用两种类型的索引,但是数字索引的返回值必须是字符串索引返回值类型的子类型
这是因为当使用number来索引时,javascript会将它转换成string然后再去索引对象
字符串索引签名能够很好的描述dictionary模式,并且它们也会确保所有属性与其返回值类型相匹配。因为字符串索引声明了obj.property 和obj["property"]两种形式都可以
7、类类型
与C#或Java里接口的基本作用一样,Typescript也能够用它来明确的强制一个类去符合某种契约
接口描述了类的公共部分,而不是公共和私有两部分,他不会帮你检查是否具有某些私有成员
7-1 类静态部分与实例部分的区别
当你操作类和接口的时候,你要知道类是具有两个类型的:静态部分的类型和实例的类型。你会注意到,当你用构造器签名去定义一个接口并试图定义一个类去实现这个接口时会出错
这里是因为一个类实现了一个接口时,只对其实例部分进行类型检查。constructor 存在于类的静态部分,所以不再检查的范围
因此我们 应该直接操作类的静态部分。看下面的例子,我们定义了两个接口
如果 两个类中的构造函数签名的参数类型与接口中的参数类型不一致,则会报错
8、继承接口
和类一样,接口也可以相互继承。这让我们能够从一个接口里赋值成员到另一个接口里,可以更灵活的将接口分割到可重用的模块里
9、混合类型
先前我们提过,接口能够描述Javascript里丰富的类型。因为JavaScript其动态灵活的特点,有时你会希望一个对象可以同时具有上面提到的多种类型
如下:一个对象可以同时做为函数和对象使用,并带有额外的属性。
10、接口继承类
当接口继承了一个类类型时,它会继承类的成员但不包括其实现。就好像接口声明了所有类中存在的成员,但并没有提供具体实现一样,接口同样会继承类的private和protected成员。这意味着当你创建了一个接口继承了一个拥有私有或受保护的成员的类时,这个接口类型只能被这个类或其子类所实现(因为其子类也可以继承基类的private和protected成员,但注意:子类继承了private成员,但是在子类中不能访问其继承的private成员)