在通常情况下,接口是用来定义一些规范,使用这些接口,就必须实现按照接口中的规范来走。
接口的作用:在面向对象编程中,接口是一种规范的定义,它定义了行为和动作的规范。在程序设计中,接口起到了一种限制和规范的作用,接口定义了某一批类所需要遵守的规范,接口不关心这些类的内部状态数据,也不关心这些类里方法的实现细节,它只规定这批类里必须提供某些方法,提供这些方法的类就可以满足实际需要。typescript中的接口类似于java,同时还增加了更灵活的接口类型,包括属性、函数、可索引和类等。
基本用法
const getFullName = (obj:{firstName:string, lastName:string}) => {
return `${obj.firstName} ${obj.lastName}`;
}
getFullName({
firstName: 'li',
lastName: 'si'
});
1
2
3
4
5
6
7
2
3
4
5
6
7
定义接口的关键字是interface
。我们现在就来定义一个接口:
interface Person {
name: string,
age: number
}
let tom:Person = {
name: 'lisi',
age: 22
}
1
2
3
4
5
6
7
8
9
2
3
4
5
6
7
8
9
上述例子中,我们定义了一个接口Person,接着定义了一个变量tom,它的类型是Person。这样,我们就约束了tom的形状必须和接口Person一致。接口一般首字母大写。
interface NameInfo {
firstName:string,
lastName:string
}
const getFullName = ({firstName, lastName}:NameInfo) => {
return `${firstName} ${lastName}`;
}
getFullName({
firstName: 'li',
lastName: 'si'
});
1
2
3
4
5
6
7
8
9
10
11
2
3
4
5
6
7
8
9
10
11
属性接口(对json对象的约束)
// ts中自定义方法传入参数,对json进行约束
function sayName(info:{name:string}):string {
return info.name;
}
console.log(sayName(111)); // 错误写法,传入的参数不是对象
console.log(sayName({age: 12})); // 错误写法,传入的参数对象中没有name属性
console.log(sayName({name: 'lisi'})); // 正确写法
1
2
3
4
5
6
7
8
2
3
4
5
6
7
8
// 对批量方法传入参数进行约束
// 接口:行为和动作的规范,对批量方法进行约束
// 就是传入对象的约束:属性接口
interface FullName {
firstName:string; // 约束
secondName:string;
}
// 约束firstName和secondName是必传参数
// 必须传入对象参数
function sayName(name:FullName) {
console.log(name.firstName + '---' + name.secondName + '---' + name.age);
}
let obj = {
firstName: 'li',
secondName: 'si',
age: 12
};
// 传入的参数必须包含firstName和secondName
sayName(obj);
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
可选属性
interface FullName {
firstName:string; // 约束
secondName?:string; // 可选参数
}
// 必须传入对象参数
function sayName(name:FullName) {
console.log(name.firstName);
}
let obj = {
firstName: 'li'
};
// 传入的参数必须包含firstName,但是secondName可选
sayName(obj);
1
2
3
4
5
6
7
8
9
10
11
12
13
2
3
4
5
6
7
8
9
10
11
12
13
多余属性检查
interface Vegetable {
color?:string,
type:string
}
const getVegetables = ({color, type}:Vegetable) => {
return `A ${color ? (color + ' ') : ''}${type}`;
}
console.log(getVegetables({
type: 'tomato',
color: 'red',
size: 123 // 报错-多余属性
}));
1
2
3
4
5
6
7
8
9
10
11
12
13
14
2
3
4
5
6
7
8
9
10
11
12
13
14
绕开多余属性检查
使用类型断言
interface Vegetable {
color?:string,
type:string
}
const getVegetables = ({color, type}:Vegetable) => {
return `A ${color ? (color + ' ') : ''}${type}`;
}
console.log(getVegetables({
type: 'tomato',
color: 'red',
size: 123
} as Vegetable)); // 使用类型断言来绕开多余属性检查
1
2
3
4
5
6
7
8
9
10
11
12
13
14
2
3
4
5
6
7
8
9
10
11
12
13
14
使用索引签名
interface Vegetable {
color?:string,
type:string,
[prop:string]:any // 索引签名
}
const getVegetables = ({color, type}:Vegetable) => {
return `A ${color ? (color + ' ') : ''}${type}`;
}
console.log(getVegetables({
type: 'tomato',
color: 'red',
size: 123
}));
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
2
3
4
5
6
7
8
9
10
11
12
13
14
15
使用类型兼容性
interface Vegetable {
color?:string,
type:string
}
const getVegetables = ({color, type}:Vegetable) => {
return `A ${color ? (color + ' ') : ''}${type}`;
}
const vegetableInfo = {
type: 'tomato',
color: 'red',
size: 123
};
console.log(getVegetables(vegetableInfo));
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
只读属性
interface Vegetable {
color?:string,
readonly type:string
}
const vegetableObj:Vegetable = {
type: 'tomato'
}
vegetableObj.type = 'apple'; // 报错
1
2
3
4
5
6
7
8
9
10
2
3
4
5
6
7
8
9
10
// 数组只读
interface ArrInter {
0: number,
readonly 1: string
}
const arrInter: ArrInter = [1, 'a'];
arrInter[1] = 'we'; // 报错
1
2
3
4
5
6
7
2
3
4
5
6
7
应用
// 属性接口应用--ajax请求封装
interface Config {
type:string,
url:string,
data?:string, // 可选属性
dataType:string
}
function ajax(config:Config) {
let xhr = new XMLHttpRequest();
xhr.open(config.type, config.url, true);
xhr.send(config.data);
xhr.onreadystatechange = function() {
if (xhr.readyState === 4 && xhr.status === 200) {
if (config.dataType === 'json') {
console.log(JSON.parse(xhr.responseText));
}
else {
console.log(xhr.responseText);
}
}
}
}
ajax({
type: 'get',
data: 'name=lisi',
url: 'http://www.baidu.com',
dataType: 'json'
});
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
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
函数类型接口
函数类型接口:对方法传入的参数和返回值进行约束。
// 函数类型接口:可以实现批量约束
// 加密的函数类型接口
interface encrypt {
// 接收两个string类型参数key和value,返回值也是string类型
(key:string, value:string):string;
}
// md5方法必须遵循encrypt接口规范:key、value以及返回值都是string类型
let md5:encrypt = function(key:string, value:string):string {
// 模拟md5操作
return key + value;
}
console.log(md5('name', 'lisi'));
1
2
3
4
5
6
7
8
9
10
11
12
2
3
4
5
6
7
8
9
10
11
12
可索引接口
可索引接口:对数组或者对象的约束(不常用)。
interface UserArr {
// 定义了索引是数字,值是字符串的数组接口
[index:number]:string
}
let arr22:UserArr = ['111', '222'];
1
2
3
4
5
6
2
3
4
5
6
interface UserObj {
// 定义了索引是字符串,值是字符串的对象接口
[index:string]:string
}
let obj22:UserObj = {name: 'lisi'};
1
2
3
4
5
6
2
3
4
5
6
类类型接口
类类型接口:对类的约束,和抽象类有点相似。
// 类类型接口
interface Animal {
name:string; // 属性
eat(str:string):string; // 方法
}
// 实现接口(必须要有name属性和eat方法)
class Dog implements Animal {
name:string;
constructor(name:string) {
this.name = name;
}
eat():string {
return this.name;
}
}
let dog2 = new Dog('xiaohuang');
console.log(dog2.eat());
class Cat implements Animal {
name:string;
constructor(name:string) {
this.name = name;
}
eat(food:string):string {
return `${this.name}吃${food}`;
}
}
let cat = new Cat('xiaohua');
console.log(cat.eat('黄花鱼')); // xiaohua吃黄花鱼
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
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
接口继承
接口扩展:接口可以继承接口。
interface Animal {
eat():string; // Animal接口有一个eat方法
}
// Person接口继承Animal接口
interface Person extends Animal {
work():string;
}
class Woman implements Person {
public name:string;
constructor(name:string) {
this.name = name;
}
eat():string {
return `${this.name}爱吃米饭`;
}
work():string {
return `${this.name}爱工作`;
}
}
let woman = new Woman('lisi');
console.log(woman.eat());
console.log(woman.work());
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
继承类并实现接口
interface Animal {
eat():string;
}
interface Person extends Animal {
work():string;
}
class Programmer {
public name:string;
constructor(name:string) {
this.name = name;
}
coding():string {
return `${this.name}爱写代码`;
}
}
// 继承类并实现接口
class Woman extends Programmer implements Person {
constructor(name:string) {
super(name);
}
// 实现接口的eat和work方法
eat():string {
return `${this.name}爱吃米饭`;
}
work():string {
return `${this.name}爱工作`;
}
}
let woman = new Woman('lisi');
console.log(woman.coding());
console.log(woman.eat());
console.log(woman.work());
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
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
再来看个例子:
interface Vegetables {
color: string
}
// Tomato从Vegetables继承了color属性
interface Tomato extends Vegetables {
size: number
}
interface Carrot {
length: number
}
const tomato: Tomato = {
size: 123,
color: 'red'
}
const carrot: Carrot = {
length: 123
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
混合类型接口
interface Counter { // 定义一个函数接口,该函数有一个count属性
(): void,
count: number
}
const getCounter = (): Counter => {
const c = () => { c.count++ }
c.count = 0;
return c;
}
const counter: Counter = getCounter();
counter();
console.log(counter.count); // 1
counter();
console.log(counter.count); // 2
counter();
console.log(counter.count); // 3
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17