还是记不住 TS 的 interface 和 type 的区别?

这知识它怎么就不进脑子 😡

不知道是不是上了年纪,上个月刚看过的知识点,转头就忘的一干二净 🤷‍♂️

遥想初中的时候,记英语单词那叫一个 6 🤔️,单词在哪个单元的哪个位置我都能记得一清二楚。反观现在,时不时的怀疑自己是不是脑子坏掉了,或是提前得了老年痴呆症 🤨

基于这个背景,我还是把知识点记下来吧 😭,好记性不如烂笔头,Let's go! 🚀

🚩 其实关于 TS 中 type 和 interface 的区别,人家官方早有解释:

Type aliases and interfaces are very similar, and in many cases you can choose between them freely. Almost all features of an interface are available in type, the key distinction is that a type cannot be re-opened to add new properties vs an interface which is always extendable.

类型别名和接口非常相似,在许多情况下,您可以在它们之间自由选择。接口几乎所有的特性都可以在类型中使用,关键的区别在于类型不能重新打开以添加新属性,而接口总是可扩展的。

去看文档 🙄️ 「Differences Between Type Aliases and Interfaces

下面我们对 type 和 interface 进行逐一的了解,最后举例并讨论一下二者的区别,Go!🚀

1. Type Aliases 类型别名

我们在写 TS 的时候,遇到「对象类型」或者「联合类型」,可以直接在类型注释中编写,比如:

let userId: number | string // 联合类型
let adminId: number | string // 联合类型

这种直接在类型注释中编写联合类型的方式非常方便,但是缺点是后续的维护成本比较大

举个 🌰:我们要对 👆 的两种 id 再加一个 boolean 类型(先别管合不合理),那我们就需要手动给上面两种 id 都加上 boolean,这很不方便。如果再有更多的 id 类型需要一起改的话,那简直就是灾难 🔥

基于这个背景,我们希望:被多次使用的相同的类型,可以对它进行提取,通过单个名称引用。于是乎,就有了 Type Aliases — 类型别名 🎉

type ID = number | string; // 后续维护 + boolean 也非常方便

let userId: ID
let adminId: ID

刚才举例的是「联合类型」的类型别名,同理,「对象类型」也是一样的。实际上,可以使用类型别名为任何类型命名,比如 `type ID = number`,这也是 Type 和 interface 的第一个不同点:「type 适用于基本类型,interface 一般不行」。这里简单提一下,后面我们再聊 👌

2. Interface 接口

interface 接口声明是命名「对象类型」的另一种方法:

type Point { // type aliases
  x: number;
  y: number;
}

interface Point { // interface
  x: number;
  y: number;
}
function printCoord(pt: Point) {
  console.log("The coordinate's x value is " + pt.x);
  console.log("The coordinate's y value is " + pt.y);
}
printCoord({ x: 100, y: 100 });

其实上面这个 Point 类型,用 type 和 interface 声明的作用是一样的,TypeScript 只关心我们传递给 printCoord 值的结构 - 它只关心它具有预期的属性。

3. Type vs Interface

我们在文章的一开始也提到过了,官方明确解释:

类型别名和接口非常相似,在许多情况下,您可以在它们之间自由选择。几乎所有 interface 的功能在 中 type 都可用,关键区别在于不能重新打开类型来添加新属性,而接口始终是可扩展的。

3.1 声明范围的区别

type A = string
interface B = string // 'string' only refers to a type, but is being used as a value here.

Interfaces may only be used to declare the shapes of objects, not rename primitives.

🚩 结论:interface 只能用于声明对象类型,而不能用于重命名原始类型

3.2 组合方式的区别

interface Animal { name: string; }
// 通过 extends 关键字扩展接口
interface Bear extends Animal { honey: boolean; }

type Animal = { name: string; }
// 通过 & 扩展类型
type Bear = Animal & { honey: boolean; }

🚩 结论:interface 使用 extends 来实现继承,type 使用 & 来实现交叉类型

3.3 扩展方式的区别

interface Window { title: string; }
// 向现有 interface 添加新字段
interface Window { ts: TypeScriptAPI; }

type Window = { title: string; }
// 类型创建后无法更改
type Window = { ts: TypeScriptAPI; } // Error: Duplicate identifier 'Window'.

Type aliases may not participate in declaration merging, but interfaces can.

🚩 结论:interface 可以通过重复声明来扩展,type 一个类型只能声明一次

3.4 命名方式的不同

type Name = string
const name: Name = 'erha'
typeof name // string -> 并没有新创建类型

interface Person {
    name: string;
}
const user: Person = { age: 'erha' }
// Type '{ age: string; }' is not assignable to type 'Person'.
//  Property 'name' is missing in type '{ age: string; }'.
// 错误信息中提示 ‘Person’ 是新类型

Interface names will always appear in their original form in error messages, but only when they are used by name.

🚩 结论:interface 会创建新的类型名,type 只是创建类型别名,并不新创建类型

总结

  1. interface 只能用于声明对象类型,而不能用于重命名原始类型
  2. interface 使用 extends 来实现继承,type 使用 & 来实现交叉类型
  3. interface 可以通过重复声明来扩展,type 一个类型只能声明一次
  4. interface 会创建新的类型名,type 只是创建类型别名,并不新创建类型
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值