TypeScript 里 interface 和 type 的区别 Hybrid Types with both type alias and interface 区别 Extends and implements 元祖 Tuples 什么时候用 interface,什么时候用 type alias?

interface X {
    a: number
    b: string
}

type X = {
    a: number
    b: string
};

我们可以用 interface 去 extend type:

TypeScript 里 interface 和 type 的区别
Hybrid Types with both type alias and interface
区别
Extends and implements
元祖 Tuples
什么时候用 interface,什么时候用 type alias?

用 class 实现 type:

TypeScript 里 interface 和 type 的区别
Hybrid Types with both type alias and interface
区别
Extends and implements
元祖 Tuples
什么时候用 interface,什么时候用 type alias?

用 class 实现 type 和 interface 的混合:
TypeScript 里 interface 和 type 的区别
Hybrid Types with both type alias and interface
区别
Extends and implements
元祖 Tuples
什么时候用 interface,什么时候用 type alias?

type intersection 的用法,使用 & 连接多个 type:
TypeScript 里 interface 和 type 的区别
Hybrid Types with both type alias and interface
区别
Extends and implements
元祖 Tuples
什么时候用 interface,什么时候用 type alias?

使用 partial 将部分 type 的字段变成 optional:
TypeScript 里 interface 和 type 的区别
Hybrid Types with both type alias and interface
区别
Extends and implements
元祖 Tuples
什么时候用 interface,什么时候用 type alias?

您可能偶尔想要定义一个对象,它既充当函数又充当对象,并具有附加属性。

我们在这里谈论的是为函数(可调用对象)和该函数的静态属性定义类型。

看个例子:

interface Counter {
    // callable part
    (start: number): string
    // static properties
    interval: number
    reset(): void
  }
  
  const getCounter = () => {
     const counter = ((start:number) => {}) as Counter
     counter.interval = 123
     counter.reset = () => {}
     return counter
  }
  
  const callable = getCounter();
  callable(10);
  callable.reset();
  callable.interval = 5;

用 interface 定义了一个 Counter, 该类型兼有 callable 和静态属性两种特征。

最佳实践:还是分开定义吧。

callable 的定义:

TypeScript 里 interface 和 type 的区别
Hybrid Types with both type alias and interface
区别
Extends and implements
元祖 Tuples
什么时候用 interface,什么时候用 type alias?

静态属性的定义:
TypeScript 里 interface 和 type 的区别
Hybrid Types with both type alias and interface
区别
Extends and implements
元祖 Tuples
什么时候用 interface,什么时候用 type alias?

最后的 counter 类型:
TypeScript 里 interface 和 type 的区别
Hybrid Types with both type alias and interface
区别
Extends and implements
元祖 Tuples
什么时候用 interface,什么时候用 type alias?

类型与类型之间连接用 &,接口的组合用 extends.

In TypeScript, we have a lot of basic types, such as string, boolean, and number. These are the basic types of TypeScript. You can check the list of all the basic types here. Also, in TypeScript, we have advanced types and in these advanced types, we have something called type aliases. With type aliases, we can create a new name for a type but we don’t define a new type.

所以我们使用的 type 关键字,定义的只是类型别名,而不是全新的类型。

We use the type keyword to create a new type alias, that’s why some people might get confused and think that it’s creating a new type when they’re only creating a new name for a type. So, when you hear someone talking about the differences between types and interfaces, like in this article, you can assume that this person is talking about type aliases vs interfaces.

区别

在最新版本的 TypeScript 里,二者的区别越来越小。

  • Interfaces are basically a way to describe data shapes, for example, an object.

  • Type is a definition of a type of data, for example, a union, primitive, intersection, tuple, or any other type.

interface 支持 declaration merging,而 type alias 不支持。

interface Song {
  artistName: string;
};

interface Song {
  songName: string;
};

const song: Song = {
  artistName: "Freddie",
  songName: "The Chain"
};

TypeScript will automatically merge both interfaces declarations into one, so when we use this Song interface, we’ll have both properties.

TypeScript 里 interface 和 type 的区别
Hybrid Types with both type alias and interface
区别
Extends and implements
元祖 Tuples
什么时候用 interface,什么时候用 type alias?

而 type alias 不支持,会遇到编译错误:

TypeScript 里 interface 和 type 的区别
Hybrid Types with both type alias and interface
区别
Extends and implements
元祖 Tuples
什么时候用 interface,什么时候用 type alias?

Extends and implements

In TypeScript, we can easily extend and implement interfaces. This is not possible with types though.

Interfaces in TypeScript can extend classes, this is a very awesome concept that helps a lot in a more object-oriented way of programming. We can also create classes implementing interfaces.

例子:

class Car {
  printCar = () => {
    console.log("this is my car")
  }
};

interface NewCar extends Car {
  name: string;
};

class NewestCar implements NewCar {
  name: "Car";
  constructor(engine:string) {
    this.name = engine
  }
  printCar = () => {
    console.log("this is my car")
  }
};

这里接口扩展了原始类,一个新的类又实现了接口。

元祖 Tuples

元组是 TypeScript 中一个非常有用的概念,它为我们带来了这种新的数据类型,它包括两组不同数据类型的值。

TypeScript 里 interface 和 type 的区别
Hybrid Types with both type alias and interface
区别
Extends and implements
元祖 Tuples
什么时候用 interface,什么时候用 type alias?

无法用 interface 定义元祖,但 interface 内部属性可以用元祖作为数据类型。

interface Response {
  value: [string, number]
}

什么时候用 interface,什么时候用 type alias?

当您需要定义新对象或对象的方法时,接口会更好。 例如,在 React 应用程序中,当您需要定义特定组件将要接收的 props 时,最好使用接口而不是类型:

interface TodoProps {
  name: string;
  isCompleted: boolean
};

const Todo: React.FC<TodoProps> = ({ name, isCompleted }) => {
  ...
};

例如,当您需要创建函数时,类型会更好。 假设我们有一个函数将返回一个被调用的对象,这种方法更推荐使用类型别名:

type Person = {
  name: string,
  age: number
};

type ReturnPerson = (
  person: Person
) => Person;

const returnPerson: ReturnPerson = (person) => {
  return person;
};

接口与对象和方法对象更好地工作,类型更好地与函数、复杂类型等一起工作。

更多Jerry的原创文章,尽在:"汪子熙":
TypeScript 里 interface 和 type 的区别
Hybrid Types with both type alias and interface
区别
Extends and implements
元祖 Tuples
什么时候用 interface,什么时候用 type alias?