TypeScript学习笔记,五:接口

在前面的笔记中我们知道可以使用Object Type来指定参数的属性,如下:

1 function printLabel(labelledObj: {label: string}) {
2   console.log(labelledObj.label);
3 }
4 
5 var myObj = {size: 10, label: "Size 10 Object"};
6 printLabel(myObj);

这种做法也可以通过接口实现:

 1 interface LabelledValue {
 2   label: string;
 3 }
 4 
 5 function printLabel(labelledObj: LabelledValue) {
 6   console.log(labelledObj.label);
 7 }
 8 
 9 var myObj = {size: 10, label: "Size 10 Object"};
10 printLabel(myObj);

这里很有意思的一点是,传递的参数可以不实现该接口,仅仅带有接口的属性即可。

可选属性

TypeScript的接口还支持可选属性,这在之前的参数中已经说过,如下:

 1 interface SquareConfig {
 2   color?: string;
 3   width?: number;
 4 }
 5 
 6 function createSquare(config: SquareConfig): {color: string; area: number} {
 7   var newSquare = {color: "white", area: 100};
 8   if (config.color) {
 9     newSquare.color = config.collor;  // Type-checker can catch the mistyped name here
10   }
11   if (config.width) {
12     newSquare.area = config.width * config.width;
13   }
14   return newSquare;
15 }
16 
17 var mySquare = createSquare({color: "black"});  

我们传递的类型可带有也可不带有可选的属性。

函数类型

这里在之前其实已经说到了,如果你对C#比较熟悉的话,可以将函数类型看做C#中的委托,如下:

 1 interface SearchFunc {
 2   (source: string, subString: string): boolean;
 3 }
 4 
 5 var mySearch: SearchFunc;
 6 mySearch = function(source: string, subString: string) {
 7   var result = source.search(subString);
 8   if (result == -1) {
 9     return false;
10   }
11   else {
12     return true;
13   }
14 }

即定义为SerrchFunc类型的函数只能被赋值为在接口中定义好的参数和返回值一致的函数。

数组类型

我们可以通过接口来指定一个存放指定类型的数组:

1 interface StringArray {
2   [index: number]: string;
3 }
4 
5 var myArray: StringArray;
6 myArray = ["Bob", "Fred"];

数组类型的写法是固定的,前面表示索引,返回值表示数组中可以存放的类型,当然其实TypeScript的数组是支持泛型的,所以使用泛型会更加方便一点。

Class类型

终于说到接口最核心的使用方法了,即通过接口来规范类的类型:

 1 interface ClockInterface {
 2     currentTime: Date;
 3     setTime(d: Date);
 4 }
 5 
 6 class Clock implements ClockInterface  {
 7     currentTime: Date;
 8     setTime(d: Date) {
 9         this.currentTime = d;
10     }
11     constructor(h: number, m: number) { }
12 }

实现接口使用implements关键字,同时一个类可以实现多个接口,实现了同一接口的类都可以赋值给该接口类型的变量,这里和Java、C#等语言用法一致。

规范构造函数

这也是TypeScript中比较独特的地方了,可以通过接口来指定构造函数的参数,我们先看下面的写法:

1 interface ClockInterface {
2     new (hour: number, minute: number);
3 }
4 
5 class Clock implements ClockInterface  {
6     currentTime: Date;
7     constructor(h: number, m: number) { }
8 }

这个写法会报错,这在TypeScript中是不允许的写法。

规范构造函数的接口不能使用implemnets实现,而是作为类型存在,如下:

 1 interface ClockStatic {
 2     new (hour: number, minute: number);
 3 }
 4 
 5 class Clock  {
 6     currentTime: Date;
 7     constructor(h: number, m: number) { }
 8 }
 9 
10 var cs: ClockStatic = Clock;
11 var newClock = new cs(7, 30);

这样的写法就能达到我们想要的效果了。

接口继承

接口之间可以继承,同时支持多重继承,如下:

 1 interface Shape {
 2     color: string;
 3 }
 4 
 5 interface PenStroke {
 6     penWidth: number;
 7 }
 8 
 9 interface Square extends Shape, PenStroke {
10     sideLength: number;
11 }
12 
13 var square = <Square>{};
14 square.color = "blue";
15 square.sideLength = 10;
16 square.penWidth = 5.0;

这里要注意一下,square并不是实现了该接口的类,所以不能使用new来实现,而是使用<Square>{}的写法来创建,这里要注意一下。

混合类型

我们可以指定一个对象的类型,如下:

 1 interface Counter {
 2     (start: number): string;
 3     interval: number;
 4     reset(): void;
 5 }
 6 
 7 var c: Counter;
 8 c(10);
 9 c.reset();
10 c.interval = 5.0;