接口可以像类一样使用继承来扩展自身的功能。通过继承,我们可以从已有的接口派生出新的接口,实现代码复用和类型组合。
接口使用 extends 关键字继承另一个接口,子接口会继承父接口的所有成员。
interface Animal {
name: string
age: number
}
interface Dog extends Animal {
breed: string
}
const myDog: Dog = {
name: "小黑",
age: 3,
breed: "拉布拉多"
}
console.log(`${myDog.name} 是一只 ${myDog.breed}`)
Dog 接口继承了 Animal 的 name 和 age 属性,同时添加了自己的 breed 属性。实现 Dog 接口的对象必须包含这三个属性。
与类不同,接口可以同时继承多个接口,用逗号分隔。这种能力让接口的组合非常灵活。
interface Flyable {
fly(): void
}
interface Swimmable {
swim(): void
}
interface Runnable {
run(): void
}
interface Duck extends Flyable, Swimmable, Runnable {
name: string
}
class MallardDuck implements Duck {
name: string
constructor(name: string) {
this.name = name
}
fly(): void {
console.log(`${this.name} 飞翔`)
}
swim(): void {
console.log(`${this.name} 游泳`)
}
run(): void {
console.log(`${this.name} 奔跑`)
}
}
const duck = new MallardDuck("唐老鸭")
duck.fly()
duck.swim()
duck.run()
绿头鸭实现了 Duck 接口,而 Duck 继承了三个能力接口。这种设计方式让我们可以把不同的能力拆分成独立的接口,然后按需组合。
接口可以形成继承链,一个接口继承另一个接口,后者又可以继承其他接口。
interface Entity {
id: number
}
interface Timestamped extends Entity {
createdAt: Date
updatedAt: Date
}
interface User extends Timestamped {
name: string
email: string
}
const user: User = {
id: 1,
createdAt: new Date(),
updatedAt: new Date(),
name: "张三",
email: "zhangsan@example.com"
}
User 继承 Timestamped,Timestamped 继承 Entity,形成了三层继承关系。最终 User 接口包含了所有祖先接口的成员。
子接口可以重新定义父接口的属性,但类型必须兼容。通常用于将属性类型收窄或添加更具体的约束。
interface BaseConfig {
host: string
port: number | string
}
interface ProductionConfig extends BaseConfig {
port: number
ssl: boolean
}
const config: ProductionConfig = {
host: "api.example.com",
port: 443,
ssl: true
}
BaseConfig 中 port 可以是数字或字符串,ProductionConfig 将其收窄为只能是数字。这种覆盖是允许的,因为数字类型是 number | string 的子类型。
接口可以继承类,这会继承类的所有成员,包括私有和受保护成员。这种用法相对少见,但在某些场景下很有用。
class Component {
private id: string
protected state: any
constructor(id: string) {
this.id = id
this.state = {}
}
}
interface IPage extends Component {
render(): void
}
class HomePage implements IPage {
private id: string
protected state: any
constructor() {
this.id = "home"
this.state = {}
}
render(): void {
console.log("渲染首页")
}
}
实现 IPage 接口的类必须包含 Component 的私有和受保护成员,因为接口继承了类的完整结构。
接口可以同时继承其他接口和类,实现更复杂的类型组合。
interface Serializable {
serialize(): string
}
class BaseEntity {
id: number
constructor(id: number) {
this.id = id
}
}
interface Document extends BaseEntity, Serializable {
title: string
content: string
}
class Article implements Document {
id: number
title: string
content: string
constructor(id: number, title: string, content: string) {
this.id = id
this.title = title
this.content = content
}
serialize(): string {
return JSON.stringify({
id: this.id,
title: this.title,
content: this.content
})
}
}
Document 接口同时继承了类和接口,Article 类必须实现所有继承来的成员。
接口继承在实际项目中常用于构建分层的类型体系。比如定义 API 响应的通用结构:
interface ApiResponse<T> {
code: number
message: string
}
interface PagedResponse<T> extends ApiResponse<T> {
data: T[]
total: number
page: number
pageSize: number
}
interface User {
id: number
name: string
}
const response: PagedResponse<User> = {
code: 200,
message: "success",
data: [
{ id: 1, name: "张三" },
{ id: 2, name: "李四" }
],
total: 100,
page: 1,
pageSize: 10
}
基础响应只包含状态码和消息,分页响应在此基础上添加了数据和分页信息。这种分层设计让类型定义更加清晰。
接口继承创建的是新的类型,而声明合并则是将同名接口的成员合并到一起。
interface Config {
host: string
}
interface Config {
port: number
}
const config: Config = {
host: "localhost",
port: 3000
}
上面两个 Config 接口会自动合并,最终包含 host 和 port 两个属性。这与继承不同,继承需要显式使用 extends 关键字。
接口继承是 TypeScript 类型系统中非常实用的特性。通过单继承和多继承,我们可以构建灵活的类型层次结构,实现代码复用和类型组合。在实际开发中,合理使用接口继承可以让类型定义更加清晰、易于维护,也便于团队协作时统一接口规范。