关注于数据值的 ‘shape’的类型检查是typescript核心设计原则。这种模式有时被称为‘鸭子类型’或者‘结构子类型化’。 。 在typescript中接口interfaces的责任就是命名这些类型,而且还是你的代码之间或者是与外部项目代码的契约。
理解interface的最好办法,就是写个hello world程序:
1
2
3
4
5
6
<code>function</code> <code>printlabel(labelledobj: {label: string}) {</code>
<code> </code><code>console.log(labelledobj.label);</code>
<code>}</code>
<code>var</code> <code>myobj = {size: 10, label: </code><code>"size 10 object"</code><code>};</code>
<code>printlabel(myobj);</code>
在这里类型检查系统会检查printlabel这个函数,printlabel函数要求传入一个包含一个label的字符串属性。上例可以了解我们传入的对象可以有多个属性,但是类型检查系统只会检查printlabel所要求的label属性是否满足其要求。
接下来我们可以进一步简化,声明一个interface来描述一个具有label字符串属性的对象:
7
8
9
10
<code>interface</code> <code>labelledvalue {</code>
<code> </code><code>label: string;</code>
<code>function</code> <code>printlabel(labelledobj: labelledvalue) {</code>
接口labelledvalue描述了上例中printlabel的所要求的类型对象。它依然代表包含一个label的字符串属性。可以看见我们利用‘shape’(行)描述了printlabel的传入参数要求。
有时不是所有定义在interface中的属性都是必须的。例如流行的”option bags”模式(option配置),使用者可以之传入部分定制化属性。如下面“option bags”模式:
11
12
13
14
<code>interface</code> <code>squareconfig { color?: string; width?: number; }</code>
<code>function</code> <code>createsquare(config: squareconfig): {color: string; area: number} {</code>
<code> </code><code>var</code> <code>newsquare = {color: </code><code>"white"</code><code>, area: 100};</code>
<code> </code><code>if</code> <code>(config.color) {</code>
<code> </code><code>newsquare.color = config.color;</code>
<code> </code><code>}</code>
<code> </code><code>if</code> <code>(config.width) {</code>
<code> </code><code>newsquare.area = config.width * config.width;</code>
<code> </code><code>return</code> <code>newsquare;</code>
<code>var</code> <code>mysquare = createsquare({color: </code><code>"black"</code><code>});</code>
带有可选属性的interface定义和c#语言很相似,以’?‘紧跟类型后边表示。
interface的可选属性可以限制那些属性是可用的,这部分能得到类型检查,以及智能感知。例如下例:
15
16
17
<code>interface</code> <code>squareconfig {</code>
<code> </code><code>color?: string;</code>
<code> </code><code>width?: number;</code>
<code> </code><code>newsquare.color = config.collor; </code><code>// 类型检查系统能识别不正确的属性collor.</code>
interfaces为了描述对象能接收的数据形(shapes)的返回。对于interface不仅难呢过描述对象的属性,也能描述函数类型。
下面是定义的interface signature是一个接收两个string的输入参数,并返回boolean的函数类型:
<code>interface</code> <code>searchfunc {</code>
<code> </code><code>(source: string, substring: string): boolean;</code>
我也可以使用函数类型的interface去描述我们的数据。下面演示如何将一个相同类型的函数赋值给interface:
<code>var</code> <code>mysearch: searchfunc;</code>
<code>mysearch = </code><code>function</code><code>(source: string, substring: string) {</code>
<code> </code><code>var</code> <code>result = source.search(substring);</code>
<code> </code><code>if</code> <code>(result == -1) {</code>
<code> </code><code>return</code> <code>false</code><code>;</code>
<code> </code><code>else</code> <code>{</code>
<code> </code><code>return</code> <code>true</code><code>;</code>
对于函数类型的interface,并不需要参数名的对应相同,如下例:
<code>mysearch = </code><code>function</code><code>(src: string, sub: string) {</code>
<code> </code><code>var</code> <code>result = src.search(sub);</code>
对于函数参数的检查,会按照参数的顺序检查对应的类型是否匹配。同时也会检查函数的返回类型是否匹配,在这个函数我们期望返回boolean类型true/false, 如果返回的是numbers或者string,则类型检查系统会提示返回值类型不匹配。
类似于函数类型,typescript也可以描述数组类型。在数组类型中有一个’index’类型其描述数组下标的类型,以及返回值类型描述每项的类型,如下:
<code>interface</code> <code>stringarray {</code>
<code> </code><code>[index: number]: string;</code>
<code>var</code> <code>myarray: stringarray;</code>
<code>myarray = [</code><code>"bob"</code><code>, </code><code>"fred"</code><code>]</code>
index的支持两种类型,分别是字符串和数值类型. 我们可以限制index的类型,同时也可以检查index项的返回值类型。
index的类型签名可以描述常用的数组或者是‘dictionary’(字典序)模式,这点会强制所有的属性都需要和其返回值匹配。下例中length属性不匹配这点,所以类型检查会给出一个错误:
<code>interface</code> <code>dictionary {</code>
<code> </code><code>[index: string]: string;</code>
<code> </code><code>length: number; </code><code>// error, the type of 'length' is not a subtype of the indexer</code>
在c#和java中interface是很常使用的类型系统,其用来强制其实现类符合其契约。在typescript中同样也可以实现:
<code>interface</code> <code>clockinterface {</code>
<code> </code><code>currenttime: date;</code>
<code>class</code> <code>clock </code><code>implements</code> <code>clockinterface {</code>
<code> </code><code>constructor(h: number, m: number) { }</code>
同样也可以在interface中实现函数类型的契约,并要求clas实现此函数。如下例的‘settime’函数:
<code> </code><code>settime(d: date);</code>
<code> </code><code>settime(d: date) {</code>
<code> </code><code>this</code><code>.currenttime = d;</code>
<code> </code><code>}</code>
interface描述的的是class的公开(public)部分,而不是私有部分.
当使用类和接口的时候,我们需要知道类有两种类型:static(静态)部分和instance(实例)部分。如果尝试一个类去实现一个带有构造签名的interface,typescript类型检查会提示你错误。
<code> </code><code>new</code> <code>(hour: number, minute: number);</code>
这是因为一个类去实现接口的时候,只有instance(实例)的部分才会被检查。而构造函数属于静态部分,所以不会被类型检查。
相反你可以直接在类中实现这些(static)静态部分,如下例:
<code>interface</code> <code>clockstatic {</code>
<code>new</code> <code>(hour: number, minute: number);</code>
<code>class</code> <code>clock {</code>
<code>currenttime: date;</code>
<code>constructor(h: number, m: number) { }</code>
<code>var</code> <code>cs: clockstatic = clock; </code><code>var</code> <code>newclock = </code><code>new</code> <code>cs(7, 30);</code>
和类一样,接口也能集成其他的接口。这相当于复制接口的所有成员。接口的集成是的我们可以自由的抽象和分离到可重用的组件。
<code>interface</code> <code>shape {</code>
<code> </code><code>color: string;</code>
<code>interface</code> <code>square </code><code>extends</code> <code>shape {</code>
<code> </code><code>sidelength: number;</code>
<code>var</code> <code>square = <square>{};</code>
<code>square.color = </code><code>"blue"</code><code>;</code>
<code>square.sidelength = 10;</code>
一个interface可以同时集成多个interface,实现多个接口成员的合并。
<code>interface</code> <code>penstroke {</code>
<code> </code><code>penwidth: number;</code>
<code>interface</code> <code>square </code><code>extends</code> <code>shape, penstroke {</code>
<code>square.penwidth = 5.0;</code>
如前边提到的一样,在interface几乎可以描述javascript世界的一切对象。因为javascript是一个动态,灵活的脚本语言,所以偶尔也希望一个对象能够描述一些多个类型.
下面是一个混合式描述函数,对象以及额外属性的实例:
<code>interface</code> <code>counter {</code>
<code> </code><code>(start: number): string;</code>
<code> </code><code>interval: number;</code>
<code> </code><code>reset(): void;</code>
<code>var</code> <code>c: counter;</code>
<code>c(10);</code>
<code>c.reset();</code>
<code>c.interval = 5.0;</code>
和第三方javascript库交互的时候,也许我们也会上面的模式来描述一个完整的类型。