在 TypeScript 中扩展类型:性能与技巧

面向初学者的在线Python训练器

轻松学习Python,无需理论负担。在浏览器中直接解决带自动检查的实践任务,无需安装任何东西。

开始课程

可以在 TypeScript 中扩展类型吗?深入探讨性能与优化



你好,朋友!如果你曾经用 TypeScript 写过代码,那么你肯定遇到过这个问题:“能否像扩展接口一样扩展类型?”这个问题在 Stack Overflow 上获得了数千次浏览,这并非没有原因。看起来很简单:接口通过 extends 扩展,而类型通过交叉类型 (&) 扩展。但其中存在细微差别,这些差别直接影响代码的性能和可读性。



今天,我们将弄清楚如何在 TypeScript 中扩展类型,这与接口有何不同,以及如何在优化时避免犯错。开始吧!



Type vs Interface:永恒的较量



在讨论扩展之前,让我们先回顾一下它们的区别。接口是可以多次声明的“契约”(声明合并),而类型是任何形式的别名。两者都可以扩展,但方式不同。



如何扩展接口?

这部分大家都很熟悉:

interface Animal {  name: string;}

interface Bear extends Animal { honey: boolean;}

const bear: Bear = { name: 'Winnie', honey: true };


简单、优雅、有效。但是,如果我们想对类型做同样的事情呢?



如何扩展类型?

类型不直接支持 extends。而是使用交叉运算符 (&):

type Animal = {  name: string;};

type Bear = Animal & { honey: boolean };

const bear: Bear = { name: 'Winnie', honey: true };


看起来相似,但存在一些陷阱。让我们通过示例来探讨它们。



性能:哪个更快?



价值百万的问题:选择 interface extends 还是 type & 会影响编译和执行速度吗?剧透:会,但并非如你所想。



编译:接口胜出

TypeScript 编译接口比编译类型交叉更快。为什么?接口是“扁平”的结构,编译器可以缓存并线性处理。而类型交叉是复杂的结构,可能需要递归展开。



// 接口 - 快速interface A { a: string }interface B extends A { b: number }

// 类型 - 较慢type A = { a: string }type B = A & { b: number }


在包含数百个类型的大型项目中,差异可能很明显。但如果你只有 10-20 个实体,你几乎感觉不到。



运行时:没有区别

TypeScript 是 JavaScript 的超集。在运行时,既没有接口也没有类型。它们只存在于开发阶段。因此,对程序执行速度完全没有影响。



什么时候类型比接口更好?

尽管编译速度可能较慢,但在某些场景下类型是不可替代的:

  • 联合类型 — 类型的联合(例如,string | number)
  • 条件类型 — 条件类型(例如,T extends string ? 'yes' : 'no')
  • 映射类型 — 属性转换(例如,{ [K in keyof T]: boolean })


接口无法处理这些。但如果你只需要扩展一个对象——接口是首选。



优化:如何避免搬起石头砸自己的脚



现在进入最有趣的部分。如何编写可扩展的类型,既不会拖慢编译速度,也不会让同事困惑?



规则 1:对象用接口,其他用类型

这是黄金标准。如果你描述一个对象的形状——使用 interface。如果你需要联合类型、交叉类型或泛型魔法——使用 type。



// 好interface User {  id: number;  name: string;}

type Status = 'active' | 'inactive';type Admin = User & { role: 'admin' };<

博客

书籍推荐