第213题:TypeScript 中 Interface 与 Type 的区别?在写 TypeScript 的时候,该用哪个比较好?

发布于 2022-07-30 15:57:15 字数 184 浏览 218 评论 3

interface 接口只声明成员方法,不做实现。是一种描述对象或函数的东西。你可以把它理解为形状,一个对象需要有什么样的属性,函数需要什么参数或返回什么样的值,数组应该是什么样子的,一个类和继承类需要符合什么样的描述等等。下文分七个部分,一起看一下对象接口、函数接口、可索引类型接口、类接口是如何定义的,以及接口的继承、定义混合类型的接口和继承类的接口是如何使用的。

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

当爱已成负担 2022-05-04 10:04:58

接口 与 类型别名 的异同点

相同点

1. 都可以描述对象或函数

// 接口
interface Sister {
  name: string;
  age: number;
}

interface SetSister {
  (name: string, age: number): void;
}

// 类型别名
type Sister = {
  name: string;
  age: number;
};

type SetSister = (name: string, age: number) => void;

2. 都可以扩展

interface 和 type 可以混合扩展,也就是说 interface 可以扩展 typetype 也可以扩展 interface

但需要注意的是,接口的扩展是继承( extends )。类型别名的扩展就是交叉类型(通过 & 实现)

// 接口
interface SisterAn {
    name: string;
}

// 类型别名
type SisterRan = {
    age: number;
}
// 接口扩展接口
interface Sister extends SisterAn {
    age: number;
}
// 类型别名扩展类型别名
type SisterPro = SisterRan & {
    name: string;
}
// 接口扩展类型别名
interface Sister extends SisterRan {
    name: string;
}
// 类型别名扩展接口
type SisterPro = SisterAn & {
    age: number;
}

区别

官方 中这样介绍两者的区别:

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.

意思就是说几乎接口的所有特性都可以通过类型别名来实现,主要区别在于:

1. 不同的声明范围

与接口不同,可以为任意的类型创建类型别名

类型别名的右边可以是任何类型,包括基本类型、元祖、类型表达式( &| 等);而在接口声明中,右边必须为变量结构。例如,下面的类型别名就不能转换成接口

type Name = string
type Text = string | { text: string };
type Coordinates = [number, number];

2. 不同的扩展形式

接口是通过继承的方式来扩展,类型别名是通过 & 来扩展

// 接口扩展
interface SisterAn {
    name: string;
}
interface Sister extends SisterAn {
    age: number;
}

// 类型别名扩展
type SisterRan = {
    age: number;
}
type SisterPro = SisterRan & {
    name: string;
}

这里需要注意的是,接口扩展时,typescript 会检查扩展的接口是否可以赋值给被扩展的接口

// 接口扩展
interface SisterAn {
    name: string;
    age: string
}

interface Sister extends SisterAn {
    name: string;
    age: number;
}
// 报错:
//  Interface 'Sister' incorrectly extends interface 'SisterAn'.
//  Types of property 'age' are incompatible.
//  Type 'number' is not assignable to type 'string'

但使用交集类型时就不会出现这种情况

// 类型别名扩展
type SisterRan = {
	name: string;
    age: string;
}
type SisterPro = SisterRan & {
    name: string;
    age: number;
}

类型别名扩展时,typescript 将尽其所能把扩展和被扩展的类型组合在一起,而不会抛出编译时错误

3. 不同的重复定义表现形式

接口可以定义多次,多次的声明会自动合并

interface Sister {
    name: string;
}
interface Sister {
    age: number;
}

const sisterAn: Sister = {
    name: 'sisterAn'
} 
// 报错:Property 'age' is missing in type '{ name: string; }' but required in type 'Sister'

const sisterRan: Sister = {
    name: 'sisterRan', 
    age: 12
}
// 正确

但是类型别名如果定义多次,会报错

type Sister = { // Duplicate identifier 'Sister'
    name: string;
}

type Sister = { // Duplicate identifier 'Sister'
    age: number;
}

如何选择 Interface 、 Type

虽然 官方 中说几乎接口的所有特性都可以通过类型别名来实现,但建议优先选择接口,接口满足不了再使用类型别名,在 typescript 官网 Preferring Interfaces Over Intersections 有说明,具体内容如下:

大多数时候,对象类型的简单类型别名的作用与接口非常相似

interface Foo { prop: string }

type Bar = { prop: string };

但是,一旦你需要组合两个或多个类型来实现其他类型时,你就可以选择使用接口扩展这些类型,或者使用类型别名将它们交叉在一个中(交叉类型),这就是差异开始的时候。

  • 接口创建一个单一的平面对象类型来检测属性冲突,这通常很重要! 而交叉类型只是递归的进行属性合并,在某种情况下可能产生 never 类型
  • 接口也始终显示得更好,而交叉类型做为其他交叉类型的一部分时,直观上表现不出来,还是会认为是不同基本类型的组合。
  • 接口之间的类型关系会被缓存,而交叉类型会被看成组合起来的一个整体。
  • 最后一个值得注意的区别是,在检查到目标类型之前会先检查每一个组分。

出于这个原因,建议使用接口/扩展扩展类型而不是创建交叉类型。

- type Foo = Bar & Baz & {
-     someProp: string;
- }
+ interface Foo extends Bar, Baz {
+     someProp: string;
+ }

简单的说,接口更加符合 JavaScript 对象的工作方式,简单的说明下,当出现属性冲突时:

// 接口扩展
interface Sister {
    sex: number;
}

interface SisterAn extends Sister {
    sex: string;
}
// index.ts(5,11): error TS2430: Interface 'SisterAn' incorrectly extends interface 'Sister'.
//  Types of property 'sex' are incompatible.
//    Type 'string' is not assignable to type 'number'.
// 交叉类型
type Sister1 = {
    sex: number;
}

type Sister2 = {
    sex: string;
}

type SisterAn = Sister1 & Sister2;
// 不报错,此时的 SisterAn 是一个'number & string'类型,也就是 never

原文

忆沫 2022-05-04 08:31:29

参考: Differences Between Type Aliases and Interfaces

  1. 扩展,都可以扩展,但是语法不同,interface 通过extends,但是type通过 交叉类型 &
  2. 声明合并:interface可以实现声明合并,但是type不行
懒的傷心 2022-05-03 21:00:55
  • interface 只能定义对象类型。type声明可以声明任何类型。
  • interface 能够声明合并,两个相同接口会合并。Type声明合并会报错
  • type可以类型推导

查看整理链接

~没有更多了~

关于作者

半世蒼涼

暂无简介

0 文章
0 评论
788 人气
更多

推荐作者

遂心如意

文章 0 评论 0

5513090242

文章 0 评论 0

巷雨优美回忆

文章 0 评论 0

junpengz2000

文章 0 评论 0

13郎

文章 0 评论 0

qq_xU4RDg

文章 0 评论 0

    我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
    原文