TypeScript:类型与接口

2025-05-27

TypeScript:类型与接口

在我最近的一个 PR 中,我把所有interfaces都改成了types,因为 s 的数量已经超过了types 。在审核中,我被要求撤销这个更改。我照做了,但我也想知道interface之间到底有什么区别。让我们来弄清楚这个问题。我在本文中使用最新的 TS (v3.5.1) 作为示例。interfacetype

相似之处

记录

interface IAnimal {
  name: string;
}

type Animal = {
  name: string;
};
Enter fullscreen mode Exit fullscreen mode

泛型

interface IAnimal<P = string> {
  name: P;
}

type Animal<P = string> = {
  name: P;
};
Enter fullscreen mode Exit fullscreen mode

交叉路口

type Robot = {
  power: number;
};

interface IRobot {
  name: string;
}

interface IRoboAnimal1 extends IAnimal, IRobot {}
interface IRoboAnimal2 extends IAnimal, Robot {}
interface IRoboAnimal3 extends Animal, IRobot {}
interface IRoboAnimal4 extends Animal, Robot {}

type RoboAnimal1 = Animal & Robot;
type RoboAnimal2 = Animal & IRobot;
type RoboAnimal3 = IAnimal & Robot;
type RoboAnimal4 = IAnimal & IRobot;
Enter fullscreen mode Exit fullscreen mode

implements

class Dog implements IAnimal {
  name: string = "good dog";
}

class Cat implements Animal {
  name: string = "Where is my food, human?";
}
Enter fullscreen mode Exit fullscreen mode

扩展类

class Control {
  private state: any;
}

interface ISelectableControl extends Control {
  select(): void;
}

type SelectableControl = Control & {
  select: () => void;
};
Enter fullscreen mode Exit fullscreen mode

功能

type Bark = (x: Animal) => void;

interface iBark {
  (x: Animal): void;
}
Enter fullscreen mode Exit fullscreen mode

和泛型:

type Bark = <P = Animal>(x: P) => void;

interface iBark {
  <P = Animal>(x: P): void;
}
Enter fullscreen mode Exit fullscreen mode

递归声明

type Tree<P> = {
  node: P;
  leafs: Tree<P>[];
};

interface ITree<P> {
  node: P;
  leafs: ITree<P>[];
}
Enter fullscreen mode Exit fullscreen mode

精确的

type Close = { a: string };
const x: Close = { a: "a", b: "b", c: "c" };
// Type '{ a: string; b: string; c: string; }' is not assignable to type 'Close'.

interface IClose {
  a: string;
}
const y: IClose = { a: "a", b: "b", c: "c" };
// Type '{ a: string; b: string; c: string; }' is not assignable to type 'IClose'.
Enter fullscreen mode Exit fullscreen mode

可转位

type StringRecord = {
  [index: string]: number;
};

interface IStringRecord {
  [index: string]: number;
}
Enter fullscreen mode Exit fullscreen mode

差异

原始类型

您只能使用类型来为原始类型添​​加别名

type NewNumber = number;

interface INewNumber extends number {}
// 'number' only refers to a type, but is being used as a value here.

// this works
interface INewNumber extends Number {}
// but don't forget that 1 instanceof Number === false;
Enter fullscreen mode Exit fullscreen mode

元组

不能用接口声明元组

type Tuple = [number, number];

interface ITuple {
  0: number;
  1: number;
}

[1, 2, 3] as Tuple; // Conversion of type '[number, number, number]' to type '[number, number]' may be a mistake

[1, 2, 3] as ITuple; // Ok
Enter fullscreen mode Exit fullscreen mode

不相交联合

不相交联合仅适用于以下类型:

type DomesticAnimals = { type: "Dog" } | { type: "Cat" };
Enter fullscreen mode Exit fullscreen mode

并且不能使用不相交的联合类型extends

interface IDomesticAnimals extends DomesticAnimals {}
// An interface can only extend an object type or intersection of object types with statically known members
Enter fullscreen mode Exit fullscreen mode

new

您可以声明new

interface IClassyAnimal {
  new (name: string);
}
Enter fullscreen mode Exit fullscreen mode

它没有像你期望的那样工作

class Parrot implements IClassyAnimal {
  name: string;
  constructor(name: string) {
    this.name = name;
  }
}
// Class 'Parrot' incorrectly implements interface 'IClassyAnimal'.
//  Type 'Parrot' provides no match for the signature 'new (name: string): void'.
Enter fullscreen mode Exit fullscreen mode

constructor似乎也不起作用

interface IClassyAnimal {
  constructor(name: string): void;
}

class Parrot implements IClassyAnimal {
  name: string;
  constructor(name: string) {
    this.name = name;
  }
}
// Class 'Parrot' incorrectly implements interface 'IClassyAnimal'.
//  Types of property 'constructor' are incompatible.
//    Type 'Function' is not assignable to type '(name: string) => void'.
//      Type 'Function' provides no match for the signature '(name: string): void'.
Enter fullscreen mode Exit fullscreen mode

每个范围只有一个声明

每个范围只能声明一次类型

type Once = { a: string };
type Once = { b: string };
// Duplicate identifier 'Once'.
Enter fullscreen mode Exit fullscreen mode

您可以在每个范围内多次声明接口(最终结果将是所有声明的总和)

interface IOnce {
  a: string;
}
interface IOnce {
  b: string;
}
Enter fullscreen mode Exit fullscreen mode

实用程序类型

大多数情况下,你会使用类型而不是接口来创建实用程序类型,例如:

export type NonUndefined<A> = A extends undefined ? never : A;
Enter fullscreen mode Exit fullscreen mode

结论

在早期版本的 TS 中,并非所有这些功能都可行,所以人们习惯了使用接口。但在最新版本的 TS 中,类型似乎更加强大,我们随时都可以使用它们🤔。还是我漏掉了什么?

TS 中有很多细微差别——有些东西可能在小示例中有效(我演示过),但在大示例中就不行了。如果我漏掉了什么,请指正

献给@thekitze

文章来源:https://dev.to/stereobooster/typescript-type-vs-interface-2n0c
PREV
寻找新技术职位时要问招聘人员的 20 个问题
NEXT
按钮