TS接口

TypeScript 的核心原则之一是对值所具有的结构进行类型检查。我们使用接口(Interfaces)来定义对象的类型。接口是对象的状态(属性)和行为(方法)的抽象(描述)

接口初探

  • 在 TypeScript 中,我们使用接口(Interfaces)来定义对象的类型
  • 接口: 是对象的状态(属性)和行为(方法)的抽象(描述)
  • 接口类型的对象
    • 多了或者少了属性是不允许的
    • 可选属性: ?
    • 只读属性: readonly
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
/**
* 需求: 创建Person, 需要对人的属性进行一定的约束
* id是number类型, 必须有, 只读的
* name是string类型, 必须有
* age是number类型, 必须有
* sex是string类型, 可以没有
*/

// 定义人的接口
interface IPerson {
id: number;
name: string;
age: number;
sex: string;
}

const person1: IPerson = {
id: 1,
name: "tom",
age: 20,
sex: "男"
};

类型检查器会查看对象内部的属性是否与 IPerson 接口描述一致, 如果不一致就会提示类型错误

可选属性

  • 接口里的属性不全都是必需的,有些是只在某些条件下存在,或者根本不存在。
  • 带有可选属性的接口与普通的接口定义差不多,只是在可选属性名字定义的后面加一个 ? 符号
1
2
3
4
5
6
interface IPerson {
id: number;
name: string;
age: number;
sex?: string;
}

可选属性的优势

  • 可以对可能存在的属性进行预定义
  • 可以捕获引用了不存在的属性时的错误
1
2
3
4
5
6
const person2: IPerson = {
id: 1,
name: "tom",
age: 20
// gender: 'male' // 可以没有
};

只读属性

一些对象属性只能在对象刚刚创建的时候修改其值,可以在属性名前用 readonly 来指定只读属性:

1
2
3
4
5
6
interface IPerson {
readonly id: number;
name: string;
age: number;
sex?: string;
}

一旦赋值后再也不能被改变了

1
2
3
4
5
6
7
8
const person2: IPerson = {
id: 2,
name: "tom",
age: 20
// sex: '男' // 可以没有
// xxx: 12 // error 没有在接口中定义, 不能有
};
person2.id = 2; // error

readonly vs const

  • 最简单判断用 readonly 还是 const 的方法是,看要把它做为变量使用还是做为一个属性
  • 做为变量使用的话用 const,若做为属性则使用 readonly

函数类型

接口能够描述 JavaScript 中对象拥有的各种各样的外形。 除了描述带有属性的普通对象外,接口也可以描述函数类型。

  • 为了使用接口表示函数类型,给接口定义一个调用签名
  • 它就像是一个只有参数列表和返回值类型的函数定义
  • 参数列表里的每个参数都需要名字和类型
1
2
3
4
5
6
7
8
9
10
11
12
13
/**
* 接口可以描述函数类型(参数的类型与返回的类型)
*/

interface SearchFunc {
(source: string, subString: string): boolean;
}

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

console.log(mySearch("abcd", "bc"));

类实现接口

  • 接口定义后,也是可以被类实现的,使用implements
  • 如果被一个类实现,那么在之后需要传入接口的地方,都可以将这个类传入
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
28
29
30
31
32
33
34
35
36
37
38
39
40
41
interface IKun {
name: string;
age: number;
slogan: string;
playBasketball: () => void;
}

interface IRun {
running: () => void;
}

const ikun: IKun = {
name: "why",
age: 18,
slogan: "你干嘛!",
playBasketball: function () {
console.log("playing basketball");
}
};

// 作用: 接口被类实现
class Person implements IKun, IRun {
name: string;
age: number;
slogan: string;

playBasketball() {
console.log("playing basketball");
}

running() {
console.log("running");
}
}

const ikun2 = new Person();
const ikun3 = new Person();
const ikun4 = new Person();
console.log(ikun2.name, ikun2.age, ikun2.slogan);
ikun2.playBasketball();
ikun2.running();

接口的继承

  • 接口和类一样是可以进行继承的,也是使用extends关键字
  • 接口是支持多继承的(类不支持多继承)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
interface IPerson {
name: string;
age: number;
}

// 可以从其他的接口中继承过来属性
// 1.减少了相同代码的重复编写
// 2.如果使用第三库, 给我们定义了一些属性
// > 自定义一个接口, 同时你希望自定义接口拥有第三方某一个类型中所有的属性
// > 可以使用继承来完成
interface IKun extends IPerson {
slogan: string;
}

const ikun: IKun = {
name: "kun",
age: 18,
slogan: "你干嘛, 哎呦"
};