为什么应该使用类型而不是接口
这张图片是由人工智能生成的。
类型和接口 是每个 TypeScript 程序中使用的重要特性。
然而,由于类型和接口在功能上非常相似,这就引出了一个问题:哪个更好?
今天,我们将评估类型和接口,然后得出结论,说明为什么你在大多数情况下应该使用类型而不是接口。
所以,不多说了……让我们马上开始吧。
那么它们有什么区别呢?
让我们分析一下这个 Person 类型 和 接口 的定义:
type Person = {
name: string
age: number
}
interface Person {
name: string
age: number
}
很明显,类型和接口有相似的语法,关键区别在于类型使用 = 来定义对象的形状,而不是接口。
然而,事情远不止于此。
让我们深入挖掘一下,一起探索和评估类型和接口。
可扩展性
就可扩展性而言,许多人认为接口是显而易见的赢家,因为接口可以使用 extends 扩展其他接口。
// 可扩展性示例
interface Job {
job: string
}
interface Person extends Job {
name: string
age: number
}
// 使用了 Person 和 Job 的属性。
const person: Person = {
name: "John",
age: 25,
job: "全栈 Web 开发者",
}
在这里,Person 接口扩展了 Job,因此 Job 接口的属性合并到了 Person 中。
另一方面,类型也通过利用 联合 | 或 交集 & 运算符来合并现有类型,提供了可扩展性。
接口无法直接表达这种行为。
// ✅ 正常工作
type Person = {
name: string
age: number
} & { job: string }
// ❌ 不工作
interface Person {
name: string
age: number
} & { job: string }
实现
在 TypeScript 中,接口与面向对象编程(OOP)兼容,就像其他语言(例如 Java 或 C#)一样。
这意味着接口可以在类中使用 implements 实现。
现在让我们将 Person 定义为一个类,并实现一个名为 Work 的新接口,满足它们之间的约定。
// 实现示例
interface Work {
doWork: () => void
}
class Person implements Work {
name: string
age: number
constructor(name: string, age: number) {
this.name = name
this.age = age
}
// 实现 doWork 方法以满足 `Work` 接口。
doWork() {
console.log("工作中...")
}
}
const person = new Person("John", 25)
person.doWork()
因此,如果你经常使用 OOP,接口将比类型更适用,因为类型不能直接由类实现。
性能
当谈论性能时,我们指的是 TypeScript 编译器执行的 “类型检查” 性能,随着代码库规模的增加,其性能会呈指数级下降。
这就是为什么我们要对类型和接口在类型检查性能方面进行基准测试,看看哪个更优。
这是一个视频,由 Matt Pocock 解释了类型和接口之间的区别,以及在类型检查性能方面实际上 没有 类型和接口之间的任何差异。
接口为什么会有害
在 TypeScript 中,接口具有一个称为 声明合并 的独特特性。
声明合并是指 TypeScript 编译器将 两个或多个 具有相同名称的接口合并为 一个。
// 初始的 Person 接口
interface Person {
name: string
age: number
}
// 使用 "声明合并" 来完善 Person 接口
interface Person {
gender: string
}
// 使用 "合并" 接口来定义一个新的 "person"
const person: Person = { name: "John", age: 25, gender: "男性" }
一方面,这个特性允许方便地对现有接口进行细化和扩展,而不会影响其他依赖项。
另一方面,声明合并可能会对你的代码库产生有害且令人惊讶的影响,主要有以下 两个 原因:
- 优先级顺序:后面的声明总是优先于前面的声明。如果不小心,当在程序的许多部分进行声明合并时,这可能导致意外问题。
- 与类的不安全合并:由于 TypeScript 编译器不检查属性的初始化,这可能导致意外的运行时错误。
类型没有这个问题,因此更直接且安全。
结论
除非需要特定的接口行为,例如可扩展的细化或使用 OOP 进行实现,否则最好使用类型。
类型灵活、直接,并且避免与声明合并相关的问题。
与接口相比,类型在性能上也完全相同,为你提供了另一个选择类型而不是接口的理由。