TypeScript---interface接口
一.简介
interface 是对象的模板,可以看作是一种类型约定,中文译为“接口”。使用了某个模板的对象,就拥有了指定的类型结构。
如何定义一个接口:
如下面的代码所示,定义了一个接口
Person,它指定一个对象模板,拥有三个属性name、age和
adress。任何实现这个接口的对象,都必须部署这三个属性,并且必须符合规定的类型。// 定义一个接口 interface Person { name: string; age: number; adress: string; }如何使用:
实现该接口很简单,只要指定它作为对象的类型即可。
// 定义一个接口 interface Person { name: string; age: number; adress: string; } // 与type的使用方式一致 let person: Person = { name: "Tom", age: 25, adress: "China", };方括号运算符可以取出 interface 某个属性的类型。
// 定义一个接口 interface Person { name: string; age: number; adress: string; } type x = Person["name"]; // 方括号运算符可以取出 name 属性的类型。 let p: x = "Tom"; console.log(typeof p); // string
interface 可以表示对象的各种语法,它的成员有 5 种形式。
- 对象属性
- 对象的属性索引
- 对象方法
- 函数
- 构造函数
1.对象属性
interface Person {
name: string;
age: number;
}
如果属性是可选的,就在属性名后面加一个问号。
interface Person {
name: string;
age: number;
adress?: string; // 可选属性
}
let person: Person = {
name: "Tom",
age: 25,
};
如果属性是只读的,需要加上readonly修饰符。
interface Person {
name: string;
age: number;
readonly adress: string; // 只读属性
}
let person: Person = {
name: "Tom",
age: 25,
adress: "China",
};
person.adress = "USA"; // 编译器报错,只读属性不能被修改

2.对象属性索引(索引签名):
interface StringArray {
[index: number]: string;
}
3.对象方法(方法签名):
interface Greeter {
greet(message: string): void;
}
对象的方法共有三种写法:
// 写法一
interface A {
f(x: boolean): string;
}
// 写法二
interface B {
f: (x: boolean) => string;
}
// 写法三
interface C {
f: { (x: boolean): string };
}
4.函数类型:
interface Add {
(x: number, y: number): number;
}
5.构造函数类型:
interface 内部可以使用new关键字,表示构造函数。
interface ClockConstructor {
new (hour: number, minute: number): ClockInterface;
}
interface ClockInterface {
tick(): void;
}
二.interface 的继承
interface 可以继承其他类型,主要有下面几种情况。
1.interface 继承 interface
interface 可以使用extends关键字,继承其他 interface。
extends关键字会从继承的接口里面拷贝属性类型,这样就不必书写重复的属性。
interface Animal {
name: string;
}
interface Dog extends Animal {
breed: string;
}
如上面代码所示:Dog继承Animal,所以Dog有两个属性,一个是父接口,一个是子接口
interface 允许多重继承。
interface Style { color: string; } interface Shape { name: string; } interface Circle extends Style, Shape { radius: number; }上面示例中,
Circle同时继承了Style和Shape,所以拥有三个属性color、name和radius。多重接口继承,实际上相当于多个父接口的合并
注意:
(1).如果子接口与父接口存在同名属性,那么子接口的属性会覆盖父接口的属性。注意,子接口与父接口的同名属性必须是类型兼容的,不能有冲突,否则会报错。
interface Foo {
id: string;
}
interface Bar extends Foo {
id: number; // 报错
}
(2).多重继承时,如果多个父接口存在同名属性,那么这些同名属性不能有类型冲突,否则会报错。
interface Foo {
id: string;
}
interface Bar {
id: number;
}
// 报错
interface Baz extends Foo, Bar {
type: string;
}
2.interface 继承 type
type student = {
id: number;
name: string;
};
// 继承student接口,并且添加age属性
interface people extends student {
age: number;
}
在上面的代码中,people继承student接口,并且添加age属性;
注意,如果type命令定义的类型不是对象,interface 就无法继承。
3.interface 继承 class
interface 还可以继承 class,即继承该类的所有成员。
class Point {
x: number = 0;
y: number = 0;
}
interface Point3D extends Point {
z: number;
}
三.接口合并
多个同名接口会合并成一个接口。
interface User {
name: string;
}
interface User {
age: number;
}
// 合并后等价于:
/*
interface User {
name: string;
age: number;
}
*/
为什么要这样设计:
这样的设计主要是为了兼容 JavaScript 的行为。JavaScript 开发者常常对全局对象或者外部库,添加自己的属性和方法。那么,只要使用 interface 给出这些自定义属性和方法的类型,就能自动跟原始的 interface 合并,使得扩展外部类型非常方便。
就比如下面的代码,Web 网页开发经常会对
windows对象和document对象添加自定义属性,但是 TypeScript 会报错,因为原始定义没有这些属性。解决方法就是把自定义属性写成 interface,合并进原始定义。interface Window { hello: string; } window.hello = "world"; console.log(window); console.log(window.hello); // "world"
注意:
同名接口合并时,同一个属性如果有多个类型声明,彼此不能有类型冲突。
interface Person {
id: number;
name: string;
}
interface Person {
id: string; // error: id should be number
}

四.interface 与 type 的异同
1.相同点
-
都可以用来描述对象、函数、数组等结构类型。
// 对象 type Person = { name: string; }; let person: Person = { name: "胖猫", }; console.log(person.name); // 输出: 胖猫 interface student { name: string; } let stu: student = { name: "ikun", }; console.log(stu.name); // 输出: ikun // 数组 type person_arr = Person[]; let person_arr: person_arr = [ { name: "Alice", }, { name: "Bob", }, ]; console.log(person_arr[0].name); // 输出: Alice console.log(person_arr[1].name); // 输出: Bob interface student_arr { name: string; } let stu_arr: student_arr[] = [ { name: "Jane", }, { name: "Mike", }, ]; console.log(stu_arr[0].name); // 输出: Jane console.log(stu_arr[1].name); // 输出: Mike // 函数 type add = (x: number, y: number) => number; let add: add = (x, y) => x + y; console.log(add(2, 3)); // 输出: 5 interface add_interface { (x: number, y: number): number; } let add_interface: add_interface = (x, y) => x + y; console.log(add_interface(2, 3)); // 输出: 5 // ....... -
都可以通过扩展组合多个类型。(interface自动合并,type需要&操作)
interface Person { name: string; } interface Person { age: number; } let person: Person = { name: "Alice", age: 25, }; type Person2 = { name: string; } & { age: number; }; let person2: Person2 = { name: "Bob", age: 30, };
2.不同点
(1)type能够表示非对象类型,而interface只能表示对象类型(包括数组、函数等)。
(2)interface可以继承其他类型,type不支持继承。
继承的主要作用是添加属性,type定义的对象类型如果想要添加属性,只能使用&运算符,重新定义一个类型。
(3)同名interface会自动合并,同名type则会报错。也就是说,TypeScript 不允许使用type多次定义同一个类型。
这表明,interface 是开放的,可以添加属性,type 是封闭的,不能添加属性,只能定义新的 type。
(4)interface不能包含属性映射(mapping),type可以
(5)this关键字只能用于interface。
(6)type 可以扩展原始数据类型,interface 不行。
(7)interface无法表达某些复杂类型(比如交叉类型和联合类型),但是type可以。
下面的这个图片来自官网:

| 差异点 | interface |
type |
|---|---|---|
| 是否能表示非对象类型 | 不能 | 可以(如联合、原始类型等) |
| 是否支持继承 | 支持继承(extends) | 不直接支持继承 |
| 同名定义合并 | 会合并 | 会报错 |
| 属性映射(Mapped Types) | 不支持 | 支持 |
this 类型使用 |
支持 | 不支持 |
| 扩展原始类型 | 不行 | 可以 |
| 表达复杂类型 | 限制较多 | 更灵活(支持交叉、联合等) |
五.总结
综上所述,如果有复杂的类型运算,那么没有其他选择只能使用type;一般情况下,interface灵活性比较高,便于扩充类型或自动合并,建议优先使用。
注意:使用带有 extends 通常可以提高编译器的性能 的接口,而不是带有交叉的类型别名
更多推荐



所有评论(0)