TypeScript学习总结之接口

接口 interface

在 TypeScript 学习总结之基础类型 那一章节中,我稍微学习了一下 接口 interface, 对它有了初步了解, 接下来总结的是 TS 文档接口这一章节。

函数类型

以官方文档代码为例, 我分析了几种函数注解的方式:

方式一:

(最常见的)

1
2
3
4
5
6
7
8
9
interface SearchFunc {
(source: string, subString: string): boolean;
}

let mySearch: SearchFunc;
mySearch = function (source: string, subString: string) {
let result = source.search(subString);
return result > -1;
};

方式二:

// 这种注解方式, 你会发现它同样把函数的实现方式也给实现了。 这样做不太好

1
2
3
4
5
6
7
8
9
10
11
12
13
14
interface SearchFunc {
(source: string, subString: string): boolean;
}

// let mySearch: SearchFunc;
// mySearch = function (source: string, subString: string) {
// let result = source.search(subString);
// return result > -1;
// }

function mySearch(source: string, subString: string): boolean {
let result = source.search(subString);
return result > -1;
}

方式三:

// 通过 表达式的方式 你会发现 代码会显得特别长

1
2
3
4
5
6
7
8
9
10
11
interface SearchFunc {
(source: string, subString: string): boolean;
}

let mySearch: (source: string, subString: string) => boolean = function (
source: string,
subString: string
): boolean {
let result = source.search(subString);
return result > -1;
};

方式四:

把方式三 给抽离出来看看

  1. 使用类型别名:
  2. 使用 接口 interface (这个和方式一 就一模一样了))

// 1.类型别名 方式

1
2
3
4
5
6
7
// 类型别名 方式
type SearchFunc = (source: string, subString: string) => boolean;

let mySearch: SearchFunc = function (source: string, subString: string): boolean {
let result = source.search(subString);
return result > -1;
};

// 2.接口 interface 方式 (最常见的)

1
2
3
4
5
6
7
8
9
// 接口 interface
interface SearchFunc {
(source: string, subString: string): boolean;
}

let mySearch: SearchFunc = function (source: string, subString: string): boolean {
let result = source.search(subString);
return result > -1;
};

可索引的类型 接口

可索引的类型的接口 指的就是 数组类型的接口

可索引类型具有一个 索引签名,它描述了对象索引的类型,还有相应的索引返回值类型。

TypeScript 支持两种索引签名:字符串和数字。 可以同时使用两种类型的索引,但是数字索引的返回值必须是字符串索引返回值类型的子类型。

示例:

1
2
3
4
5
6
7
8
9
10
11
interface NumberArray {
[index: number]: number;
}

let obj: NumberArray = {
0: 1, // 其实这个索引值 0 1 2 都是字符串 虽然定义的是数字, 但终究会转换成string
1: 2,
2: 3,
};

let arr: NumberArray = [1, 2, 3, 4];

因为当使用 number 来索引时, JavaScript 终究会将它转换成 string 然后再去索引对象。

由此可知:在索引签名中, string 是包含着 number 的

再举个例子:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
class Animal {
name: string;
}
class Dog extends Animal {
breed: string;
}

// 错误:使用数值型的字符串索引,有时会得到完全不同的Animal!
// interface NotOkay {
// [x: number]: Animal;
// [x: string]: Dog;
// }

// success
interface NotOkay {
[x: string]: Animal; //因为Animal是父类,只能是string
[x: number]: Dog; // Dog继承了Animal 但索引又想和Animal一样,那么把它换成number即可
}

再看看 索引的返回值, 索引签名中 规定是什么类型就是什么类型,

因为 对象中 key 一定是字符串,但 value 不一定是

1
2
3
4
5
6
interface NumberDictionary {
[index: string]: number;
length: number; // 可以,length是number类型
// name: string // 错误,`name`的类型与索引类型返回值的类型不匹配
name: number; // OK
}

类 类型接口

对 类 的一部分行为进行抽象;

类实现所有接口中的属性和方法 && 对比 对象类: 抽象方法需要实现

与 C#或 Java 里接口的基本作用一样,TypeScript 也能够用它来明确的强制一个类去符合某种契约。

1
2
3
4
5
6
7
8
9
10
11
12
interface ClockInterface {
currentTime: Date; // 定义属性
setTime(d: Date): void; // 定义方法
}
// implements 实现 专门用来实现接口
class Clock implements ClockInterface {
currentTime = new Date(); // 实现实现
setTime() {
// 实现方法
}
constructor(h: number, m: number) {}
}

类继承+类类型接口 示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
interface Alarm {
// 警告器
alert(): void;
}

interface Light {
// 车灯
color: string;
lightOn(): void;
lightOff(): void;
}

class Door {}
// 继承 Door (门) 这个类 然后实现 Alarm 接口
class securityDoor extends Door implements Alarm {
alert() {
console.log('咚咚咚');
}
}

// car 要实现 这个俩个接口的方法和属性
class car implements Alarm, Light {
color = 'red';
alert() {}
lightOn() {}
lightOff() {}
}

类静态部分与实例部分的区别

类是具有两个类型的:静态部分的类型和实例的类型

而 constructor 存在于类的静态部分, 所以不再检查的范围内

因此,类静态部分和实例部分需要单独分开来做

示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
// 定于一个  闹钟接口
interface ClockInterface {
currentTime: Date;
getTime(hour: number, mins: number): any;
}
// 定于一个 闹钟构造函数接口
interface ClockConstructor {
new (hour: number, mins: number): any;
}

// Clock 去实现 闹钟接口ClockInterface
class Clock implements ClockInterface {
currentTime = new Date();
getTime() {}
}

// 定义一个构造函数 createClock 通过构造函数检查构造函数的方式 去 new 一个C
function createClock(C: ClockConstructor, hour: number, mins: number) {
return new C(hour, mins);
}

// 实例化
let clock = createClock(Clock, 12, 12);

接口继承接口

因为 接口是对对象的形状进行描述; 所以接口可以继承接口,

和类一样,接口也可以相互继承。 这让我们能够从一个接口里复制成员到另一个接口里,可以更灵活地将接口分割到可重用的模块里。

1
2
3
4
5
6
7
8
9
10
11
12
13
interface Shape {
color: string;
}

interface Square extends Shape {
sideLength: number;
}

// 类型断言
// let square = <Square>{};
let square = {} as Square;
square.color = 'blue';
square.sideLength = 10;

混合类型

函数类型的 interface ,添加属性的方式来实现 对象的 interface

相当于 函数类型的 interface + 对象类型的 interface

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
interface Counter {
(start: number): string; // 有点像构造函数
interval: number;
reset(): void;
}

function getCounter(): Counter {
let counter = <Counter>function (start: number) {}; // 断言 可以理解为 给 counter 初始值
counter.interval = 123;
counter.reset = function () {};
return counter;
}

let c = getCounter();
c(10);
c.reset();
c.interval = 5.0;

接口继承类

  1. 接口可以接触接口
  2. 接口可以继承类
  3. 类可以实现接口
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
//   定义 类
class Control {
private state: any;
}

// 接口继承类
interface SelectableControl extends Control {
select(): void;
}

// 类继承类然后实现接口
class Button extends Control implements SelectableControl {
select() {}
}

// 类继承接口
class TextBox extends Control {
select() {}
}

// 错误:“Image”类型缺少“state”属性。
// class Images implements SelectableControl {
// select() { }
// }

最后,看了俩遍文档还是有点迷。。。。。 以后多练习练习