接口 interface

89 阅读4分钟

interface 简介

interface 对象的模板,类型约定,使用了某个模板的对象,就拥有了指定的类型结构

interface Person {
	firstName: string;
	lastName: string;
	age: number;
}
const p: Person = {
	firstName: "John",
	lastName: "Smith",
	age: 25,
};
// 接口Person及符合Person接口的对象p, p必须拥有Person所定义的所有属性才符合规定

可以通过方括号取出interface的某个属性, 对于type 定义的模板,也是同样可以用方括号获取属性定义

type Age = Person["age"]; // number
type Person2 = {
	firstName: string;
	lastName: string;
	age: number;
};
type Age2 = Person2["age"]; // number

接口表示对象成员的五种形式: 对象属性、对象的属性索引、对象方法、函数、构造函数

  • 对象属性 可选属性就加上问号,只读属性加上readonly
interface Point {
	x: number;
	y?: number;
	readonly a: string;
}
  • 对象属性索引 属性索引有string、number、symbol三种类型,一个接口,只能定义一个字符串索引
interface A {
	[prop: string]: number;
}
// 数值索引就是数组类型
interface A2 {
	[prop: number]: string;
}
const obj: A2 = ["a", "b", "c"];
// 若一个接口同时定义数值和字符串索引,则数值索引需要服从于字符串索引
interface A3 {
	[prop: string]: number;
	[prop: number]: string; // 报错
}
interface BB {
	[prop: string]: number;
	[prop: number]: number; // 正确
}
  • 对象方法
// 写法一
interface A4 {
	f(x: boolean): string;
}
// 写法二
interface B2 {
	f: (x: boolean) => string;
}
// 写法三
interface C {
	f: { (x: boolean): string };
}
// 属性名表达式写法
const f = "f";
interface A5 {
	[f](x: boolean): string;
}
// 接口定义重载,
// 函数的实现需要在接口外在实现,重载方法可以使用泛型或者类型运算符等实现,尽量少使用
interface A6 {
	f(): number;
	f(x: boolean): boolean;
	f(x: string, y: string): string;
}
  • 函数
interface Add {
	(x: number, y: number): number;
}
const myAdd: Add = (x, y) => x + y;
  • 构造函数
interface ErrorConstructor {
	new (message?: string): Error;
}

interface 继承

interface 继承 interface,使用关键字extends

interface Style {
	color: string;
}
interface Shape {
	name: string;
}
interface Circle extends Style {
	radius: number;
}
// 可以多重继承
interface Circle2 extends Style, Shape {
	radius: number;
}

继承时,如果有同名属性,子接口属性会覆盖父接口属性,以自己的属性为准, 前提是类型必须兼容,不兼容会报错,多重继承同属性名类型也必须相同,否则会报错

interface Foo {
	id: string;
}
interface Bar extends Foo {
	id: number; // 报错
}

interface 继承 type。 定义的对象,同样使用关键字 extends

type Country = {
	name: string;
	capital: string;
};
interface CountryWithPop extends Country {
	population: number;
}

interface继承类class,会继承类的所有成员,含有私有成员和保护成员的类被继承将无法实例化

class CL {
	x: string = "";

	y(): boolean {
		return true;
	}
}

interface B extends CL {
	z: number;
}
const b: B = {
	x: "",
	y: function () {
		return true;
	},
	z: 123,
};

接口合并

多个同名接口会合并成一个接口

同名接口合并,如果有相同的属性,同样不能有类型冲突,否则会报错 方法名同名但是不同的类型声明,会发生函数重载

interface Box {
	height: number;
	width: number;
}
interface Box {
	length: number;
}
const box: Box = {
	height: 10,
	width: 20,
	length: 30,
};

interface 与 type 异同

interface和type命令都可以表示对象类型,很多对象类型两者皆可定义,几乎所有的interface都可以使用type命令

type Country1 = {
	name: string;
	capital: string;
};
interface Country2 {
	name: string;
	capital: string;
}

但是interface和type还是有不同点,具体如下 1、type可以表示非对象类型,interface只能表示对象类型(数组,对象) 2、interface可以继承其他类型,type不支持继承 type定义的对象添加属性,只能使用&运算符重新定义类型

type Animal = {
	name: string;
};
type Bear = Animal & {
	honey: boolean;
};
// interface可以使用extends继承type,type也可以用&扩展新的类型

3、同名interface会自动合并,同名type会报错

type A1 = { foo: number }; // 报错
type A1 = { bar: number }; // 报错
interface A2 {
	foo: number;
}
interface A2 {
	bar: number;
}
const obj2: A2 = {
	foo: 1,
	bar: 1,
};

4、interface不能包含属性映射,type可以

interface Point2 {
	x: number;
	y: number;
}
// 正确
type PointCopy1 = {
	[Key in keyof Point2]: Point2[Key];
};
// 报错
interface PointCopy2 {
	[Key in keyof Point2]: Point2[Key];
};

5、type可以扩展原始数据类型(扩充后赋值难进行,无意义),interface不行

// 正确
type MyStr = string & {
	type: "new";
};
// 报错
interface MyStr2 extends string {
	type: "new";
}

6、interface无法表达某些复杂类型(联合类型和交叉类型)

type A7 = {
	/* ... */
};
type B7 = {
	/* ... */
};

type AorB = A7 | B7;
type AorBwithName = AorB & {
	name: string;
};

7、this关键字只能作用于interface

interface Foo2 {
	add(num: number): this;
}
class Calculator implements Foo2 {
	result = 0;
	add(num: number) {
		this.result += num;
		return this;
	}
}
// 报错
type Foo = {
	add(num: number): this;
};

相对来说,interface使用起来灵活性更高,便于扩充类型或者自动合并,但是涉及到复杂类型运算,type更方便