在TypeScript中何时使用类型别名或接口

274 阅读3分钟

TypeScript中的类型别名和接口有类似的功能。在这篇文章中,我们将讨论哪种方法最适合于不同的使用情况:

Type Aliases v Interfaces 表示原始类型

类型别名可以表示原始类型,但接口不能:

type Name = string;

赢家类型别名

值得注意的是,一般来说,直接使用原始类型而不是对其进行别名更简单。

表示数组

类型别名和接口都可以表示数组。

我们来比较一下这两种方法的语法:

type Names = string[];

interface Names {
  [index: number]: string;
}

类型别名的方法更简洁,更清晰。

胜利者类型别名

值得注意的是,直接使用数组类型而不是对其进行别名,往往更简单。

表示图元

赢家。类型别名可以表示元组类型,但接口不能:

type Point = [number, number];

赢家类型别名

表示函数

类型别名和接口都可以表示函数。

让我们来比较一下两种方法的语法:

type Log = (message: string) => void;

interface Log {
  (message: string): void;
}

类型别名的方法更简洁、更清晰。

赢家类型别名

创建联合类型

类型别名可以表示联合类型,但接口不能:

type Status = "pending" | "working" | "complete";

代表对象

到目前为止,类型别名已经和接口擦身而过。然而,接口的优势在于代表对象。

我们来比较一下两种方法的语法:

type Person = {
  name: string;
  score: number;
};

interface Person {
  name: string;
  score: number;
}

类型别名的方法又要简洁一些,但等价运算符 (=) 可能会导致语句被混淆为变量赋值到对象字面。

赢家平手

组成对象

类型别名和接口都可以将对象组合在一起。

我们来比较一下这两种方法的语法:

type Name = {
  firstName: string;
  lastName: string;
};
type PhoneNumber = {
  landline: string;
  mobile: string;
};
type Contact = Name & PhoneNumber;

interface Name {
  firstName: string;
  lastName: string;
}
interface PhoneNumber {
  landline: string;
  mobile: string;
}
interface Contact extends Name, PhoneNumber {}

类型别名的方法更简明。

类型别名可以组合接口,反之亦然:

type Name = {
  firstName: string;
  lastName: string;
};
interface PhoneNumber {
  landline: string;
  mobile: string;
}
type Contact = Name & PhoneNumber;

不过只有类型别名可以组合联合类型:

type StringActions =
  | { type: "loading" }
  | { type: "loaded"; data: string[] };
type NumberActions =
  | { type: "loading" }
  | { type: "loaded"; data: number[] };
type Actions = StringActions & NumberActions;

胜利者类型别名

编写一个库

接口有一个重要的特性,而类型别名没有,那就是声明合并:

interface ButtonProps {
  text: string;
  onClick: () => void;
}
interface ButtonProps {
  id: string;
}

这对于在第三方库中添加缺失的类型信息非常有用。如果你正在编写一个库,并希望允许这种能力,那么接口是唯一的选择。

胜利者接口

总结

类型别名通常比接口有更多的功能和更简洁的语法。然而,接口对对象有很好的语法,你可能已经习惯了其他语言的这个概念。

重要的是,无论使用哪种方法,都要保持一致,这样代码就不会混乱了。