Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 6848aa3

Browse files
committed
更新类与接口章节,详细说明接口继承类的原理
1 parent fb9b4c5 commit 6848aa3

File tree

4 files changed

+658
-520
lines changed

4 files changed

+658
-520
lines changed

.vscode/settings.json

Lines changed: 4 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -3,21 +3,8 @@
33
"editor.tabSize": 4,
44
"editor.formatOnSave": true,
55
"typescript.tsdk": "node_modules/typescript/lib",
6-
"eslint.autoFixOnSave": false,
7-
"eslint.validate": [
8-
"javascript",
9-
"javascriptreact",
10-
{
11-
"language": "vue",
12-
"autoFix": false
13-
},
14-
{
15-
"language": "typescript",
16-
"autoFix": false
17-
},
18-
{
19-
"language": "typescriptreact",
20-
"autoFix": false
21-
}
22-
]
6+
"editor.codeActionsOnSave": {
7+
"source.fixAll": true
8+
},
9+
"eslint.validate": ["javascript", "javascriptreact", "typescript", "typescriptreact", "vue"]
2310
}

advanced/class-and-interfaces.md

Lines changed: 135 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212

1313
```ts
1414
interface Alarm {
15-
alert();
15+
alert(): void;
1616
}
1717

1818
class Door {
@@ -35,12 +35,12 @@ class Car implements Alarm {
3535

3636
```ts
3737
interface Alarm {
38-
alert();
38+
alert(): void;
3939
}
4040

4141
interface Light {
42-
lightOn();
43-
lightOff();
42+
lightOn(): void;
43+
lightOff(): void;
4444
}
4545

4646
class Car implements Alarm, Light {
@@ -64,25 +64,29 @@ class Car implements Alarm, Light {
6464

6565
```ts
6666
interface Alarm {
67-
alert();
67+
alert(): void;
6868
}
6969

7070
interface LightableAlarm extends Alarm {
71-
lightOn();
72-
lightOff();
71+
lightOn(): void;
72+
lightOff(): void;
7373
}
7474
```
7575

76-
上例中,我们使用 `extends` 使 `LightableAlarm` 继承 `Alarm`
76+
这很好理解,`LightableAlarm` 继承了 `Alarm`,除了拥有 `alert` 方法之外,还拥有两个新方法 `lightOn``lightOff`
7777

7878
## 接口继承类
7979

80-
接口也可以继承类
80+
常见的面向对象语言中,接口是不能继承类的,但是在 TypeScript 中却是可以的
8181

8282
```ts
8383
class Point {
8484
x: number;
8585
y: number;
86+
constructor(x: number, y: number) {
87+
this.x = x;
88+
this.y = y;
89+
}
8690
}
8791

8892
interface Point3d extends Point {
@@ -92,43 +96,144 @@ interface Point3d extends Point {
9296
let point3d: Point3d = {x: 1, y: 2, z: 3};
9397
```
9498

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` 类型是等价的。
96166

97-
[之前学习过](../basics/type-of-function.md#接口中函数的定义),可以使用接口的方式来定义一个函数需要符合的形状
167+
所以回到 `Point3d` 的例子中,我们就能很容易的理解为什么 TypeScript 能够支持接口继承类了
98168

99169
```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;
102182
}
103183

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;
107187
}
188+
189+
let point3d: Point3d = {x: 1, y: 2, z: 3};
108190
```
109191

110-
有时候,一个函数还可以有自己的属性和方法:
192+
当我们声明 `interface Point3d extends Point` 时,`Point3d` 继承的实际上是类 `Point` 的实例的类型。
193+
194+
换句话说,我们实际上是定义了一个接口 `Point3d` 继承另一个接口 `PointInstanceType`
195+
196+
所以这种用法和接口继承接口没有什么本质的区别。
197+
198+
值得注意的是,`PointInstanceType` 相比于 `Point`,缺少了 `constructor` 方法,这是因为声明 `Point` 类时创建的 `Point` 类型是不包含构造函数的。另外,除了构造函数是不包含的,静态属性/方法也是不包含的(实例的类型当然不应该包括构造函数和静态属性/方法):
111199

112200
```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+
}
117221
}
118222

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;
124227
}
125228

126-
let c = getCounter();
127-
c(10);
128-
c.reset();
129-
c.interval = 5.0;
229+
let p1: Point;
230+
let p2: PointInstanceType;
130231
```
131232

233+
上例中最后的类型 `Point` 和类型 `PointInstanceType` 是等价的。
234+
235+
所以在接口继承类的时候,也只会继承它的实例属性/方法。
236+
132237
## 参考
133238

134239
- [Interfaces](http://www.typescriptlang.org/docs/handbook/interfaces.html)[中文版](https://zhongsp.gitbooks.io/typescript-handbook/content/doc/handbook/Interfaces.html)

0 commit comments

Comments
 (0)