在Typescript中,type和interface有什么区别?

155

以下这些之间有什么不同?

type Foo = { 
    foo: string 
};
interface Foo {
   foo: string;
}

4
类型无法像接口一样进行扩展。类型只是类型的别名,不能被扩展。 - PSL
4
可在此处获取指南:https://basarat.gitbooks.io/typescript/content/docs/types/type-system.html#type-alias。我将为您翻译该网页,使其更加通俗易懂,但不会改变原本的意思。 - basarat
2
我主要使用类型来处理外部数据,例如从JSON文件中读取数据,或者在编写函数而不使用面向对象类时。 - Kokodoko
1
我发现这篇文章很有用,它解释了 TypeScript 2.7 中接口和类型别名的区别 - https://medium.com/@martin_hotell/interface-vs-type-alias-in-typescript-2-7-2a8f1777af4c - Sandeep G B
1
可能是[Typescript:接口 vs 类型]的重复问题(https://dev59.com/5loU5IYBdhLWcg3wqIK0)。 - Michael Freidgeim
显示剩余2条评论
6个回答

167

接口可以被扩展

interface A {
  x: number;
}
interface B extends A {
  y: string;
}

并且还增强了

interface C {
  m: boolean;
}
// ... later ...
interface C {
  n: number;
}

然而,类型别名可以表示一些接口无法表示的内容。

type NumOrStr = number | string;
type NeatAndCool = Neat & Cool;
type JustSomeOtherName = SomeType;

通常情况下,如果你只有一个普通对象类型(如你的问题所示),接口通常是更好的选择。如果你发现自己想要编写一些无法作为接口编写的内容,或者只是想给某些东西起不同的名称,则类型别名更好。


3
类型别名可以代表一些接口无法表示的内容。对我来说,你提到的例子 NeatAndCoolJustSomeOtherName 可以创建为扩展现有 NeatCoolSomeType 类型的接口。 - Rudey
实际上,第二个和第三个示例可以通过接口来创建: “interface NeatAndCool extends Neat, Cool {}” “interface JustSomeOtherName extends SomeType {}” - peterjwest
3
扩展两个接口并不总是与交叉类型产生相同的结果,而且并非所有类型都可以被扩展(尽管所有类型都可以被别名化或放入联合类型/交叉类型)。 - Ryan Cavanaugh
1
那么类型的优势是什么?我们可以说当我们有接口时,类型就没有用处了吗? - Mostafa Saadatnia

10

放眼全局

let myAge = 25;
let totalStatesInMyCountry = 25

看一下这两个变量,它们是相等的,即 (myAge === totalStatesInMyCountry) 但是它们的上下文完全不同。

这对于typescript的typesinterfaces也是类似的情况。看看Foo

type Foo = {
    text: string
};
interface Foo {
    text: string;
}
typeinterface 中的 Foo 看起来相同,类似于 (myAge === totalStatesInMyCountry),但这只是特殊情况。它们的上下文完全不同。
什么时候应该考虑使用 interface 而不是 type
1.您正在强制执行该类必须具有这些方法。您在考虑接口而不是类型。 2.您想创建同一契约的多个实现。比如对于合同toHumanReadableNumber(number),需要不同的实现,如100000 -> 100,000100000 -> 100K100000 -> 100 Thousands。假设您通过为每个要求创建不同的类来解决此问题。您正在考虑类和接口而不是类和类型。 3.接口用于使系统松耦合,例如实现SOLID原则。 4.接口是多重继承的替代品。一个类只能从单个类继承,但可以有多个接口。 5.对于class Point{ x:number,y:number, distanceFromCenter():number},在接口的上下文中,只有distanceFromCenter():number很重要。
----------x----------
旧答案(截至2022年12月31日之前)已经在此线程中讨论过这两者之间的差异。
type Foo = {
    foo: string
};
interface Foo {
    foo: string;
}

这里type Foointerface Foo看起来十分相似,因而容易让人混淆。 interface是一个合约,要求对象包含以下属性(例如foo:string)。 interface并不是class。当编程语言不支持多重继承时,可以使用interface作为各个类之间的公共结构。
class Bar implements Foo {
    foo: string;
}

let p: Foo = { foo: 'a string' };

typeinterface在不同的上下文中使用。

let foo: Foo;
let today: Date = new Date();

这里的 foo 的类型是 Foo,而且 today 的类型是 Date。 这就像一个变量声明,它保存了其他变量的 typeof 信息。 type 就像是接口、类、函数签名、其他类型甚至值(例如 type mood = 'Good' | 'Bad')的超集。 最终,type 描述了变量可能的结构或值。

6

说“接口可以被实现”是错误的,因为类型也可以被实现。

type A = { a: string };


class Test implements A {

    a: string;
}

虽然您可以这样做,但是您无法实现一个由多种类型组成的联合类型,这实际上是非常合理的 :)

3

Types 有点像接口,反之亦然:都可以由类实现。但是它们之间还存在一些重要的区别: 1. 当 Type 被类实现时,属于 Type 的属性必须在类内初始化,而在 Interface 中必须声明。 2. 如 @ryan 所述:Interface 可以扩展另一个 Interface。Type 不行。

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

// must initialize all props - unlike interface
class Manager implements Person {
    name: string = 'John';
    age: number = 55;

    // can add props and methods
    size:string = 'm';
}

const jane : Person = {
    name :'Jane',
    age:46,

    // cannot add more proprs or methods
    //size:'s'
}

3

类型(type)在TypeScript中用于引用已经存在的类型。它不能像interface一样进行扩展。以下是type的几个示例:

type Money = number;
type FormElem = React.FormEvent<HTMLFormElement>;
type Person = [string, number, number];

你可以在类型中使用Rest和Spread:

type Scores = [string, ...number[]];
let ganeshScore = ["Ganesh", 10, 20, 30]
let binodScore = ["Binod", 10, 20, 30, 40]

然而,接口允许您创建一种新类型。

interface Person{
  name: string,
  age: number, 
}

Interface can be extended with extends keyword.
interface Todo{
  text: string;
  complete: boolean;
}

type Tags = [string, string, string]

interface TaggedTodo extends Todo{
 tags: Tags
}

1
此处为HTML代码,不做解释。原文意为:“此外,接口可以被实现。”

1
一个对象可以实现多个接口 class Thing implements Neat, Cool - Kokodoko

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接