12
12
13
13
``` ts
14
14
interface Alarm {
15
- alert();
15
+ alert(): void ;
16
16
}
17
17
18
18
class Door {
@@ -35,12 +35,12 @@ class Car implements Alarm {
35
35
36
36
``` ts
37
37
interface Alarm {
38
- alert();
38
+ alert(): void ;
39
39
}
40
40
41
41
interface Light {
42
- lightOn();
43
- lightOff();
42
+ lightOn(): void ;
43
+ lightOff(): void ;
44
44
}
45
45
46
46
class Car implements Alarm , Light {
@@ -64,25 +64,29 @@ class Car implements Alarm, Light {
64
64
65
65
``` ts
66
66
interface Alarm {
67
- alert();
67
+ alert(): void ;
68
68
}
69
69
70
70
interface LightableAlarm extends Alarm {
71
- lightOn();
72
- lightOff();
71
+ lightOn(): void ;
72
+ lightOff(): void ;
73
73
}
74
74
```
75
75
76
- 上例中,我们使用 ` extends ` 使 ` LightableAlarm ` 继承 ` Alarm ` 。
76
+ 这很好理解, ` LightableAlarm ` 继承了 ` Alarm ` ,除了拥有 ` alert ` 方法之外,还拥有两个新方法 ` lightOn ` 和 ` lightOff ` 。
77
77
78
78
## 接口继承类
79
79
80
- 接口也可以继承类 :
80
+ 常见的面向对象语言中,接口是不能继承类的,但是在 TypeScript 中却是可以的 :
81
81
82
82
``` ts
83
83
class Point {
84
84
x: number ;
85
85
y: number ;
86
+ constructor (x : number , y : number ) {
87
+ this .x = x ;
88
+ this .y = y ;
89
+ }
86
90
}
87
91
88
92
interface Point3d extends Point {
@@ -92,43 +96,144 @@ interface Point3d extends Point {
92
96
let point3d: Point3d = {x: 1 , y: 2 , z: 3 };
93
97
```
94
98
95
- ## 混合类型
99
+ 为什么 TypeScript 能够支持接口继承类呢?
100
+
101
+ 实际上,当我们在声明 ` class Point ` 时,除了会创建一个名为 ` Point ` 的类之外,同时也创建了一个名为 ` Point ` 的类型(实例的类型)。
102
+
103
+ 所以我们既可以将 ` Point ` 当做一个类来用(使用 ` new ` 创建它的实例):
104
+
105
+ ``` ts
106
+ class Point {
107
+ x: number ;
108
+ y: number ;
109
+ constructor (x : number , y : number ) {
110
+ this .x = x ;
111
+ this .y = y ;
112
+ }
113
+ }
114
+
115
+ const p = new Point (1 , 2 );
116
+ ```
117
+
118
+ 也可以将 ` Point ` 当做一个类型来用(使用 ` : Point ` 表示参数的类型):
119
+
120
+ ``` ts
121
+ class Point {
122
+ x: number ;
123
+ y: number ;
124
+ constructor (x : number , y : number ) {
125
+ this .x = x ;
126
+ this .y = y ;
127
+ }
128
+ }
129
+
130
+ function printPoint(p : Point ) {
131
+ console .log (p .x , p .y );
132
+ }
133
+
134
+ const p = new Point (1 , 2 );
135
+
136
+ printPoint (p );
137
+ ```
138
+
139
+ 这个例子实际上可以等价于:
140
+
141
+ ``` ts
142
+ class Point {
143
+ x: number ;
144
+ y: number ;
145
+ constructor (x : number , y : number ) {
146
+ this .x = x ;
147
+ this .y = y ;
148
+ }
149
+ }
150
+
151
+ interface PointInstanceType {
152
+ x: number ;
153
+ y: number ;
154
+ }
155
+
156
+ function printPoint(p : PointInstanceType ) {
157
+ console .log (p .x , p .y );
158
+ }
159
+
160
+ const p = new Point (1 , 2 );
161
+
162
+ printPoint (p );
163
+ ```
164
+
165
+ 上例中我们新声明的 ` PointInstanceType ` 类型,与声明 ` class Point ` 时创建的 ` Point ` 类型是等价的。
96
166
97
- [ 之前学习过 ] ( ../basics/type-of-function.md#接口中函数的定义 ) ,可以使用接口的方式来定义一个函数需要符合的形状 :
167
+ 所以回到 ` Point3d ` 的例子中,我们就能很容易的理解为什么 TypeScript 能够支持接口继承类了 :
98
168
99
169
``` ts
100
- interface SearchFunc {
101
- (source : string , subString : string ): boolean ;
170
+ class Point {
171
+ x: number ;
172
+ y: number ;
173
+ constructor (x : number , y : number ) {
174
+ this .x = x ;
175
+ this .y = y ;
176
+ }
177
+ }
178
+
179
+ interface PointInstanceType {
180
+ x: number ;
181
+ y: number ;
102
182
}
103
183
104
- let mySearch : SearchFunc ;
105
- mySearch = function ( source : string , subString : string ) {
106
- return source . search ( subString ) !== - 1 ;
184
+ // 等价于 interface Point3d extends PointInstanceType
185
+ interface Point3d extends Point {
186
+ z : number ;
107
187
}
188
+
189
+ let point3d: Point3d = {x: 1 , y: 2 , z: 3 };
108
190
```
109
191
110
- 有时候,一个函数还可以有自己的属性和方法:
192
+ 当我们声明 ` interface Point3d extends Point ` 时,` Point3d ` 继承的实际上是类 ` Point ` 的实例的类型。
193
+
194
+ 换句话说,我们实际上是定义了一个接口 ` Point3d ` 继承另一个接口 ` PointInstanceType ` 。
195
+
196
+ 所以这种用法和接口继承接口没有什么本质的区别。
197
+
198
+ 值得注意的是,` PointInstanceType ` 相比于 ` Point ` ,缺少了 ` constructor ` 方法,这是因为声明 ` Point ` 类时创建的 ` Point ` 类型是不包含构造函数的。另外,除了构造函数是不包含的,静态属性/方法也是不包含的(实例的类型当然不应该包括构造函数和静态属性/方法):
111
199
112
200
``` ts
113
- interface Counter {
114
- (start : number ): string ;
115
- interval: number ;
116
- reset(): void ;
201
+ class Point {
202
+ /** 静态属性,坐标系原点 */
203
+ static origin = new Point (0 , 0 );
204
+ /** 静态方法,计算与原点距离 */
205
+ static distanceToOrigin(p : Point ) {
206
+ return
207
+ }
208
+ /** 实例属性,x 轴的值 */
209
+ x: number ;
210
+ /** 实例属性,y 轴的值 */
211
+ y: number ;
212
+ /** 构造函数 */
213
+ constructor (x : number , y : number ) {
214
+ this .x = x ;
215
+ this .y = y ;
216
+ }
217
+ /** 实例方法,打印此点 */
218
+ printPoint() {
219
+ console .log (this .x , this .y );
220
+ }
117
221
}
118
222
119
- function getCounter(): Counter {
120
- let counter = <Counter >function (start : number ) { };
121
- counter .interval = 123 ;
122
- counter .reset = function () { };
123
- return counter ;
223
+ interface PointInstanceType {
224
+ x: number ;
225
+ y: number ;
226
+ printPoint(): void ;
124
227
}
125
228
126
- let c = getCounter ();
127
- c (10 );
128
- c .reset ();
129
- c .interval = 5.0 ;
229
+ let p1: Point ;
230
+ let p2: PointInstanceType ;
130
231
```
131
232
233
+ 上例中最后的类型 ` Point ` 和类型 ` PointInstanceType ` 是等价的。
234
+
235
+ 所以在接口继承类的时候,也只会继承它的实例属性/方法。
236
+
132
237
## 参考
133
238
134
239
- [ Interfaces] ( http://www.typescriptlang.org/docs/handbook/interfaces.html ) ([ 中文版] ( https://zhongsp.gitbooks.io/typescript-handbook/content/doc/handbook/Interfaces.html ) )
0 commit comments