Typescript: Interface vs Type alias

前言

Typescript用过一段时间,发现它的强大之处,值得学习。这次主要是记录一下在项目中使用类型别名与接口的区别。

论区别

根据官方文档 TypeScript Language Specification

Unlike an interface declaration, which always introduces a named object type, a type alias declaration can introduce a name for any kind of type, including primitive, union, and intersection types.

Interface types have many similarities to type aliases for object type literals, but since interface types offer more capabilities they are generally preferred to type aliases. For example, the interface type

我们可以这样写

interface Point {
    x: number;
    y: number;
}

也可以这样写

type Point = {
    x: number;
    y: number;
}

但是这样做,意味着我们会丢失以下功能:

  • 接口可以在extends或者implements使用,但对象类型文字的类型别名不能。
  • 接口可以merged declarations,但是类型别名不能。

下面我将结合例子具体说明以下,官方文档说的是什么意思。

1、Objects/functions

两者都可以用于描述对象的形状或函数签名,但是他们的语法不同.
Interface

interface Point {
    x: number;
    y: number;
}
interface SetPoint {
    (x: number, y: number): void;
}

Type alias

type Point = {
    x: number;
    y: number;
}
type SetPoint = (x: number, y: number) => void;

2、Other Types
不像一个接口,类型别名可以用于其他类型,比如primitives、unions、tuples。

//primitive
type Name = string;

//object
type PartialPointX = { x: number };
type PartialPointY = { y: number };

//union
type PartialPoint = PartialPointX | PartialPointY;

//tuple
type Data = [number, string];

3、Extend
两者都可以被继承,同时他们的语法也不同,还有,注意,interface与type alias不是互斥的,一个接口可以继承类型别名,反之亦然。(接口使用extends,类型别名使用&)

Interface extends interface

interface  PartialPointX { x: number };
interface Point extends PartialPointY { 
    y: number; 
};

Type alias extends type alias

type PartialPointX = { x: number };
type Point = PartialPointX & { y: number; };

Interface extends type alias

type PartialPointX = { x: number };
interface Point extends PartialPointX {
    y: number;
}

Type alias extends interface

interface PartialPointX { x: number; };
type Point = PartialPointX & { y: number; }; 

4、Implements
类可以使用接口或者类型别名来实现,但是请注意,类与接口被认为是static blueprints,因此,他们不能被联合类型实现或者继承。

interface Point {
  x: number;
  y: number;
}
//一个类被接口实现
class SomePoint implements Point {
  x = 1;
  y = 2;
}

type Point2 = {
  x: number;
  y: number;
}
//一个类被类型别名实现
class SomePoint2 implements Point2 {
  x = 1;
  y = 2;
}

type Point3 = {
  z: number
}
//一个类被接口与类型别名实现
class SomePoint3 implements Point, Point3 {
  x = 1;
  y = 2;
  z = 3;
} 
type PartialPoint = { x: number; } | { y: number; };
//FIXME:一个类不能被联合类型实现
class SomePartialPoint implements PartialPoint {
  x = 1;
  y = 2;
}
//FIXME:接口不能被联合类型继承
interface SomePartialPoint2 extends PartialPoint {
  z: number;
}

5、Declaration merging
不像类型别名,一个接口可以定义多次,并将被视为只有一个接口(所有的声明将会被合并)

//以下两个声明将会变成:
//interface Point { x: number; y: number; }
interface Point { x: number; };
interface Point { y: number; };

const point: Point = { x: 1, y: 2 };

那我应该为React的Props和State使用什么?

一般来说,使用类型别名还是接口,只要是一致的就可以,我个人推荐使用类型别名。

  • type Props = {} 比较短。
  • 你的语法是一致的,什么意思,就是在组合类型的时候没有混合使用类型别名与接口。
//Bad
interface Props extends OwnProps, InjectedProps, StoreProps {}
type OwnProps = {...}
type StoreProps = {...}

//Good
type Props = OwnProps & InjectedProps & StoreProps
type OwnProps = {...}
type StoreProps = {...}

总结

我们就针对的对interface与type alias做了一些对比,在项目中使用interface还是type alias,可以根据团队的规定,只要一致就可以;在写第三发库的时候,始终使用interface来定义公共的API。

参考链接

Interface vs Type alias in TypeScript 2.7
Typescript: Interfaces vs Types

此处评论已关闭