TypeScript 接口(interface)完全指南:语法、特性与实战技巧

TypeScript 接口(interface)完全指南:语法、特性与实战技巧

🔥 吃透 TypeScript ,interface 的使用方法、继承规则、接口合并,以及与 type 的核心区别

一、接口的基础用法

1. 接口的定义与实现

接口通过 interface 关键字定义,内部描述对象的属性和方法类型。任何使用该接口作为类型的对象,都必须严格遵循接口的结构约定。

typescript 复制代码
// 定义接口 Person
interface Person {
  firstName: string;
  lastName: string;
  age: number;
}

// 实现接口:对象必须包含 firstName、lastName、age 三个属性
const p: Person = {
  firstName: 'John',
  lastName: 'Smith',
  age: 25
};

// 错误示例:缺少 lastName 属性,不符合接口约定
// const p2: Person = { firstName: 'Jane', age: 22 };

2. 提取接口属性的类型

与对象类型一致,接口支持使用方括号 [] 提取某个属性的具体类型,便于单独复用该类型。

typescript 复制代码
interface Foo {
  a: string;
  b: number;
}

// 提取属性 a 的类型 → string
type AType = Foo['a'];
// 提取属性 b 的类型 → number
type BType = Foo['b'];

const aVal: AType = 'hello';
const bVal: BType = 123;

二、接口的成员类型

接口的成员包含 5 种形式:对象属性对象属性索引对象方法函数构造函数,覆盖了对象的所有常见语法。

1. 对象属性

这是接口最基础的成员类型,通过 属性名: 类型 的形式声明,支持可选属性和只读属性。

typescript 复制代码
interface Point {
  // 必选属性
  x: number;
  y: number;
  // 可选属性:属性名后加 ?
  z?: number;
  // 只读属性:属性名前加 readonly
  readonly id: string;
}

const point: Point = {
  x: 10,
  y: 20,
  id: 'P001'
  // z 可选,可省略
};

// 错误示例:只读属性 id 无法修改
// point.id = 'P002';

属性分隔规则 :属性之间可用 ;, 分隔,最后一个属性的结尾分隔符可省略。

2. 对象的属性索引

当对象的属性名不确定(如动态键名)时,可使用属性索引 描述属性名和属性值的类型,支持 stringnumbersymbol 三种索引类型。

(1)字符串索引

用于约束「属性名为字符串」的对象,所有字符串属性的类型必须符合索引声明。

typescript 复制代码
// 字符串索引:属性名为 string,属性值为 number
interface StringMap {
  [prop: string]: number;
}

const map: StringMap = {
  a: 1,
  b: 2
};

// 错误示例:属性 c 的值为 string,不符合索引类型约束
// const map2: StringMap = { a: 1, c: 'hello' };
(2)数值索引

用于约束「属性名为数值」的对象,常用来描述类数组对象或数组。

typescript 复制代码
// 数值索引:属性名为 number,属性值为 string
interface NumberMap {
  [prop: number]: string;
}

// 数组符合数值索引约束
const arr: NumberMap = ['a', 'b', 'c'];
// 类数组对象也符合约束
const obj: NumberMap = {
  0: 'x',
  1: 'y'
};
(3)索引的约束规则
  • 唯一性:一个接口中最多只能定义一个字符串索引、一个数值索引。
  • 兼容性 :若同时定义字符串索引和数值索引,数值索引的类型必须兼容字符串索引的类型(因为 JS 会将数值属性名自动转为字符串)。
typescript 复制代码
// 错误:数值索引类型(string)与字符串索引类型(number)不兼容
interface A {
  [prop: string]: number;
  [prop: number]: string;
}

// 正确:数值索引类型(number)兼容字符串索引类型(number)
interface B {
  [prop: string]: number;
  [prop: number]: number;
}

3. 对象的方法

接口中声明对象方法有三种写法,效果完全一致,推荐使用函数签名写法(更贴近方法的定义习惯)。

typescript 复制代码
// 写法 1:函数签名(推荐)
interface MethodInterface1 {
  f(x: boolean): string;
}

// 写法 2:箭头函数类型
interface MethodInterface2 {
  f: (x: boolean) => string;
}

// 写法 3:函数类型字面量
interface MethodInterface3 {
  f: { (x: boolean): string };
}

// 实现接口方法
const obj1: MethodInterface1 = {
  f(x) {
    return x ? 'true' : 'false';
  }
};
方法的重载

接口支持函数重载,即声明多个同名方法的不同参数和返回值类型,无需给出实现,只需约定类型即可。

typescript 复制代码
// 接口内声明方法重载
interface OverloadInterface {
  f(): number;
  f(x: boolean): boolean;
  f(x: string, y: string): string;
}

// 实现重载方法:需在外部定义函数实现所有重载类型
function func(): number;
function func(x: boolean): boolean;
function func(x: string, y: string): string;
function func(
  x?: boolean | string,
  y?: string
): number | boolean | string {
  if (x === undefined && y === undefined) return 1;
  if (typeof x === 'boolean') return x;
  if (typeof x === 'string' && typeof y === 'string') return x + y;
  throw new Error('参数错误');
}

// 部署重载方法
const obj: OverloadInterface = { f: func };

4. 函数

接口可以直接声明独立的函数类型,用于约束函数的参数和返回值。

typescript 复制代码
// 声明函数接口:接收两个 number 参数,返回 number
interface Add {
  (x: number, y: number): number;
}

// 实现函数接口
const myAdd: Add = (x, y) => x + y;
console.log(myAdd(1, 2)); // 输出 3

5. 构造函数

接口中使用 new 关键字可以声明构造函数类型,用于约束类的构造函数。

typescript 复制代码
// 声明构造函数接口:接收可选 string 参数,返回 Error 实例
interface ErrorConstructor {
  new (message?: string): Error;
}

// 原生 Error 类符合该接口约束
const MyError: ErrorConstructor = Error;
const err = new MyError('出错了');

三、接口的继承

接口支持通过 extends 关键字继承其他类型,实现类型复用与扩展。继承的类型可以是接口type 定义的对象类型

1. 接口继承接口

这是最常见的继承场景,子接口会继承父接口的所有成员,并可添加新成员。

typescript 复制代码
// 父接口 Shape
interface Shape {
  name: string;
}

// 子接口 Circle 继承 Shape
interface Circle extends Shape {
  radius: number; // 新增属性
}

// 实现子接口:需包含 name 和 radius
const circle: Circle = {
  name: 'circle',
  radius: 10
};
多重继承

接口支持同时继承多个父接口,多个父接口用逗号分隔,子接口会合并所有父接口的成员。

typescript 复制代码
interface Style {
  color: string;
}

interface Shape {
  name: string;
}

// 多重继承:同时继承 Style 和 Shape
interface Circle extends Style, Shape {
  radius: number;
}

// 实现:需包含 color、name、radius
const circle: Circle = {
  color: 'red',
  name: 'circle',
  radius: 10
};
继承的冲突处理
  • 子接口与父接口的同名属性必须类型兼容,否则会报错。
  • 多重继承时,多个父接口的同名属性也必须类型兼容,否则会报错。
typescript 复制代码
interface Foo {
  id: string;
}

// 错误:子接口 Bar 的 id 类型(number)与父接口 Foo 的 id 类型(string)不兼容
interface Bar extends Foo {
  id: number;
}

interface Baz {
  id: number;
}

// 错误:父接口 Foo 和 Baz 的 id 类型冲突
interface Qux extends Foo, Baz {
  type: string;
}

2. 接口继承 type

接口可以继承 type 命令定义的对象类型 ,实现类型扩展。注意:若 type 定义的是非对象类型(如联合类型),接口无法继承。

typescript 复制代码
// type 定义对象类型 Country
type Country = {
  name: string;
  capital: string;
};

// 接口继承 type,新增 population 属性
interface CountryWithPop extends Country {
  population: number;
}

const china: CountryWithPop = {
  name: '中国',
  capital: '北京',
  population: 1400000000
};

3. 接口继承类

接口可以继承类,会继承该类的所有成员(包括实例属性和方法),但不包括类的实现。

typescript 复制代码
class A {
  x: string = '';
  y(): boolean {
    return true;
  }
}

// 接口 B 继承类 A,新增 z 属性
interface B extends A {
  z: number;
}

// 实现接口 B:需包含 x、y 方法、z
const b: B = {
  x: 'hello',
  y: () => true,
  z: 123
};
注意事项

如果被继承的类包含私有成员(private)保护成员(protected),接口虽然可以继承,但无法用于对象实现(因为对象无法拥有私有/保护成员),只能被其他类实现(且需继承该父类)。

四、接口合并

TypeScript 的一个独特特性:多个同名接口会自动合并为一个接口 。这一特性非常适合扩展第三方库的类型(如为 window 对象添加自定义属性)。

1. 基本合并规则

同名接口的属性会合并,方法会形成函数重载。

typescript 复制代码
// 第一个 Box 接口
interface Box {
  height: number;
  width: number;
}

// 第二个 Box 接口
interface Box {
  length: number;
}

// 合并后的 Box 接口:包含 height、width、length
const box: Box = {
  height: 10,
  width: 20,
  length: 30
};

2. 合并的冲突处理

  • 同名属性的类型必须完全一致,否则会报错。
  • 同名方法会形成函数重载 ,且后定义的接口方法优先级更高,排在重载列表的前面。
typescript 复制代码
// 错误:同名属性 a 的类型冲突(number vs string)
interface A {
  a: number;
}
interface A {
  a: string;
}

// 方法合并形成函数重载
interface Cloner {
  clone(animal: Animal): Animal;
}
interface Cloner {
  clone(animal: Sheep): Sheep;
}
interface Cloner {
  clone(animal: Dog): Dog;
  clone(animal: Cat): Cat;
}

// 合并后等同于
interface Cloner {
  clone(animal: Dog): Dog;
  clone(animal: Cat): Cat;
  clone(animal: Sheep): Sheep;
  clone(animal: Animal): Animal;
}
特殊优先级:字面量类型参数

如果函数重载的参数是字面量类型,该方法会拥有最高优先级,排在重载列表的最前面,不受定义顺序影响。

typescript 复制代码
interface A {
  f(x: any): void;
}
interface A {
  f(x: 'foo'): boolean;
}

// 合并后:字面量类型参数的方法排在前面
interface A {
  f(x: 'foo'): boolean;
  f(x: any): void;
}

3. 接口合并的实战场景

最常见的用途是扩展全局对象的类型 ,比如为浏览器的 window 对象添加自定义属性。

typescript 复制代码
// 扩展 Document 接口,添加 foo 属性
interface Document {
  foo: string;
}

// 现在可以安全地使用 document.foo,不会报错
document.foo = 'hello';

五、接口联合类型的同名属性

当两个接口组成联合类型时,如果存在同名属性,该属性的类型会自动合并为联合类型

typescript 复制代码
interface Circle {
  area: bigint;
}

interface Rectangle {
  area: number;
}

// 联合类型:Circle | Rectangle
declare const shape: Circle | Rectangle;

// 同名属性 area 的类型为 bigint | number
const area: bigint | number = shape.area;

六、interface 与 type 的异同

interfacetype 都可以描述对象类型,在很多场景下可以互换,但两者存在核心区别,适用于不同的使用场景。

1. 相同点

  • 都可以描述对象类型,约定属性和方法的类型。
  • 都支持扩展:interface 通过 extends 扩展,type 通过交叉类型 & 扩展。
typescript 复制代码
// interface 扩展
interface Animal {
  name: string;
}
interface Bear extends Animal {
  honey: boolean;
}

// type 扩展(交叉类型)
type AnimalType = {
  name: string;
};
type BearType = AnimalType & {
  honey: boolean;
};

2. 核心区别

特性 interface type
支持的类型 仅支持对象类型(包括数组、函数) 支持任意类型(对象、原始类型、联合类型、交叉类型等)
扩展方式 通过 extends 关键字继承 通过交叉类型 & 实现扩展
声明合并 支持同名接口自动合并 不支持同名类型,重复定义会报错
属性映射 不支持映射类型 支持映射类型(如 [Key in keyof T]
this 关键字 支持在方法中使用 this 不支持在对象类型中使用 this

3. 选型建议

  • 优先使用 interface:当需要描述对象类型,且可能需要扩展或合并时(如组件 props、API 响应数据结构)。
  • 优先使用 type:当需要描述非对象类型(如联合类型、原始类型),或需要使用映射类型时。

七、核心总结

  1. 接口的本质:是对象类型的模板,约定对象的结构与类型,实现该接口的对象必须严格遵循约定。
  2. 接口的成员:支持对象属性、属性索引、方法、函数、构造函数五种形式,覆盖对象的所有常见语法。
  3. 接口的继承:可继承接口、type 对象类型、类,多重继承需注意属性类型兼容性。
  4. 接口合并:同名接口自动合并,属性合并、方法形成重载,适合扩展第三方类型。
  5. 与 type 的区别:interface 专注对象类型,支持继承和合并;type 更灵活,支持任意类型。
相关推荐
十日十行10 小时前
Linux和window共享文件夹
linux
jonjia11 小时前
模块、脚本与声明文件
typescript
jonjia11 小时前
配置 TypeScript
typescript
jonjia11 小时前
TypeScript 工具函数开发
typescript
jonjia11 小时前
注解与断言
typescript
jonjia11 小时前
IDE 超能力
typescript
jonjia11 小时前
对象类型
typescript
jonjia11 小时前
快速搭建 TypeScript 开发环境
typescript
jonjia11 小时前
TypeScript 的奇怪之处
typescript
jonjia11 小时前
类型派生
typescript