翻译: typescript 2.7中interface和type(Interface vs Type alias in TypeScript 2.7)


文章首发javascript


原文: Interface vs Type alias in TypeScript 2.7html

译者注:java

  • type alias翻译为类型别名
  • interface 不作翻译

image

常常有人在网上,在工做中,甚至在滑板公园询问我,在Typescript中定义编译时类型的类型别名interface有什么区别。ios

我之前作的第一件事就是让他们去看Typescript的手册。。。git

不幸的是在大多数时候,他们不能找到他们想要找到的东西(隐藏在“高级类型”部分)。即便你能找到它,这个信息描述的是过期的(描述的行为指针对Typescript@2.0.x版本)。github

好消息各位!你没必要在看了,这篇文章是关于什么时候使用interface类型别名的最新描述和风格指南。typescript

官方的文档说:

"类型别名 能够和interface关键字同样,然而他们有一些细微的差异。"
复制代码

这是对的bash

有什么不一样呢

第一个不一样

*interface*可以建立一个新的类型,*类型别名*不能建立一个新的类型

--例如:错误信息不能使用*类型别名*

复制代码

这是不对的!(自从Typescript 2.1开始)函数

咱们分别经过类型别名interface定义编译时类型Point,而且实现使用interface类型别名的类型参数实现两种getRectangleSquareui

image

类型别名 和 interface 声明的Point

image

使用类型别名和interface定义getRectangleArea函数的参数

image

类型别名 和 interface声明的有相同的错误

两个相同的错误以下:

// TS Error: 
// Interface:
Argument of type '{ x: number; }' is not assignable to parameter of type 'PointInterface'. Property 'y' is missing in type '{ x: number; }'.
// Type alias:
Argument of type '{ x: number; }' is not assignable to parameter of type 'PointType'. Property 'y' is missing in type '{ x: number; }'.
复制代码

第二个不一样

"第二个更加剧要的重要的区别是类型别名不能被继承或者实现"

复制代码

这个一样也是错的

咱们可以经过一个interface继承类型别名:

image

interface 继承类型别名

或者咱们使用类型别名来实现类:

image

类实现类型别名。

或者一个类可以实现继承了类型别名interface

image

ThreeDimension 继承了PointType。PointType是类型别名声明的。

咱们也能经过组合类型别名interface去实现类。

image

class 实现了interface和类型别名

第三个不一样

"3. 类型别名 不能继承/实现 其余的类型别名"
复制代码

固然这个也是错误的

  • 嗯,这个是部分正确的,可是这个表述具备误导性。

类型别名能经过交叉类型运算符**&**扩展interface或者任意有效的Typescript类型(它相似字典或者javascript对象,非原始类型)。

image

类实现了具备交叉类型的*类型别名*

咱们也能利用映射类型实现interface类型别名的各类类型转换。

让咱们经过Partial映射类型把ShapePerimeter变为可选的。

image

类实现了经过交叉运算符和类型映射定义的*类型别名*。`perimeter()`和`area()`是可选的以致于咱们不必在类中去实现他们。

弱类型检测也正常工做

image

弱类型检测定期望的同样工做。

类型别名 和 interface的混合类型

你可能偶尔想要定义一个能够充当一个具备额外属性对象或函数的对象。

咱们这里讨论的是定义函数(可执行对象),和该函数的静态属性。

当与第三方库进行交互时,能够看到这种模式,这充分描述了类型的“全貌”

混合类型的定义和实现。

它和类型别名同样工做!

经过类型别名定义混合类型。

可是有一个很是微妙的不一样。你将要在IDE中获得具体的类型信息去代替Counter类型。

image

使用类型别名和混合类型的interface的区别。

一般一个好的实践,是将咱们的混合定义分为两个部分:

  • 可调用对象(函数)类型别名

  • 静态属性对象描述

image

  • 和最终的Counte类型

image

因此类型别名和interface有什么区别呢?

1. 不能使用经过类型别名定义联合类型去实现类

这将要在编译的时候触发一个错误:

image

第一点不一样——联合运算符定义的类型不能被实现

这彻底有道理!一个图纸不能实现两个结构类型中的一个,因此在这方面没有什么好惊讶的。
复制代码

类型别名联合使用用于定义对象是有意义而且有效的。因此下面会在编译时报一个错误,由于对象必须去定义perimeter()area()两个中的一个。

image

联合类型——正确的使用对象字面量

2. 不一样经过类型别名定义的联合运算符继承interface

image

第二个不一样——联合定义类型不能被`interface`继承

一样,这个类的实现类似, interface是一个“静态”图纸——它不能实现两个结构中的一个,因此它不能被联合类型合并继承。

3. 类型别名关键字不能声明合并

interface有声明合并,可是类型别名没有。

什么是声明合并?

你能定义屡次相同的interface,这些定义将要合并为一个。

image

声明合并

这种方式对于类型别名就不成立,由于类型别名是独一无二的实体(对于全局和模块域)。

image

第三个不一样——类型别名不支持声明合并。

当咱们为没有使用Typescript创做的库写第三方环境定义的时候,经过interface的声明合并是很是重要的,若是一些定义没有的话,使用者能够选择性的扩展它。

若是咱们的库是使用Typescript写的,而且自动生成环境定义则一样使用。

这是惟一的用例,你应该老是使用interface而不是类型别名。

我应该如何使用React的Props和State?

通常的,你要使用的一致就能够(不管使用类型别名仍是interface),就我我的而言,我仍是推荐使用类型别名

  • 书写起来更短type Props = {}
  • 你的用法是统一的(你不用为了类型交叉而interface类型别名混用)
// BAD
interface Props extends OwnProps, InjectedProps, StoreProps {}
type OwnProps = {...}
type StoreProps = {...}
// GOOD
type Props = OwnProps & InjectedProps & StoreProps
type OwnProps = {...}
type StoreProps = {...}


复制代码
  • 你组件公开的props/state不能被动态替换(译者注:由于原文做者这里说的 monkey patched翻译为动态替换 what-is-monkey-patching),就这个缘由,你组件的使用者就不能利用interface的声明合并。对于扩展应该有像HOC这样明确的模式。

总结

在这遍文章中咱们学到了在Typescript 2.7interface类型别名的不一样。

有了这个,咱们得出在特定的场景中应该如何去定义编译类型的结论。

让咱们来回顾一下:

  • 类型别名 能像interface同样,可是他们有三个重要的区别(联合类型,声明合并)
  • 使用适合你或者你团队的东西,可是要保持一致
  • 当你写个库或者定义第三方环境类型的时候,在公开的API中老是使用interface
  • 在你的React组件的state/props中考虑使用类型别名
相关文章
相关标签/搜索