TS中的接口
写在之前
- 或许当我们只需要定义一个对象或类的时候,使用接口对它们进行约束是显得麻烦的,但是当我们需要定义具有同样结构的多个对象或类的时候,接口就体现出它的作用了。
接口有什么作用,什么时候应该使用接口
定义
- 我们可以先看看接口的定义,接口是对某些数据或方法的约束规则。
其他面向对象编程语言中的接口
- 接下来我们可以先了解一下其他面向对象的语言,如C++中,接口的作用,在C++中,接口用于规定子类implements接口之后,必须实现接口中规定的变量和方法(相当于是对子类结构的约束)。
C++中将接口也看成是一个类,class B : A,表示B派生自A,A是接口。
C++中会将接口定义为虚函数。
如果需要提供一个getArea接口,那么需要在Shape类中将这个方法定义为虚函数,当class Rectangle派生自接口Shape,那么Rectangle类必须实现getArea这个方法。
TS中的接口
- TypeScript中的接口是一个很灵活的概念,它相当于扩展了类似C++的面向对象编程语言中接口的行为。
- TS中的接口允许对类的结构进行约束。(类似于C++中规定了类中必须有哪些变量和方法)。
- TS中的接口也允许对对象(引用类型)的结构进行约束。(规定了对象中必须包含哪些属性)。
什么时候使用接口
- 当我们需要对引用类型的结构进行约束的时候可以使用接口。
- 当我们要声明多个类,我们可以首先定义一个接口用来规定这些类必须具有哪些变量、方法。
使用接口对引用类型进行约束
约束对象
一个简单的例子
interface Person{ name: string; age: number; } const person1: Person = { name: 'aaa', age: 1, }接口一般首字母大写。我们首先定义了一个接口Person,然后定义了一个对象perosn1,并规定它的类型是Person,这样person1中就必须包含name属性和age属性了(必须不多也不少)。
如果对象中比接口少了一些属性
const person1: Person{ name: 'aaa', } // index.ts(6,5): error TS2322: Type '{ name: string; }' is not assignable to type 'Person'. // Property 'age' is missing in type '{ name: string; }'.我们可以看到当对象person1的类型是Person时,如果person1中没有包含Person中有的age属性,那么会出现报错。
如果对象中比接口多了一些属性
const person1: Person{ name: 'aaa', age: 1, gender: 'male', } // index.ts(9,5): error TS2322: Type '{ name: string; age: number; gender: string; }' is not assignable to type 'Person'. // Object literal may only specify known properties, and 'gender' does not exist in type 'Person'.我们可以看到,当多出了Person接口中没有的属性的时候也会出现报错。
如果对象中的属性的类型和接口中的不一致
const person1: Person{ name: 123, age: 1 } //报错当person1对象中的属性name的类型和Person接口中定义的不一致的时候,也会报错。
可选的属性
interface Person{ name: string; age?: number; } const person1: Person{ name: 'aaa', }使用 ?我们可以定义可选属性,如上面的例子中,age就是一个可选属性,表示以Person接口为类型约束的对象可以包含age属性,也可以不包含age属性。
任意属性
interface Person{ name: string; age?: number; [key: string]: any; } const person1: Person = { name: 'aaa', gender: 'male', }上面的例子中,接口Person通过[key: string]表示key是string类型的,:any表示值可以是任何类型的。
任意属性的常见错误
interface Person{ name: string; age?: number; [key: string]: string; } const person1: Person = { name: 'aaa', gender: 'male', } // index.ts(3,5): error TS2411: Property 'age' of type 'number' is not assignable to string index type 'string'. // index.ts(7,5): error TS2322: Type '{ [x: string]: string | number; name: string; age: number; gender: string; }' is not assignable to type 'Person'. // Index signatures are incompatible. // Type 'string | number' is not assignable to type 'string'. // Type 'number' is not assignable to type 'string'.报错的原因是[key: string]: string同样会对上面的其他属性,如age?: number进行检查,很显然,age?: number不满足[key: string]: string的要求。
只读属性
interface Person{ readonly id: number; name: string; age?: number; [key: string]: any; } const person1: Person = { id: 89742435, name: 'aaa', gender: 'male', } person1.id = 111; // index.ts(14,5): error TS2540: Cannot assign to 'id' because it is a constant or a read-only property.我们可以使用readonly关键字声明某一个属性是只读的。这样以Person接口为类型约束的对象不能在初始化后修改id这个属性。
使用接口约束函数
一个简单的例子
interface encrypt{ (key: string,val: string): string; } var md5: encrypt = function(key: string,val: string): string{ ... return 'aaa'; }