TypeScript:类型与接口
在我最近的一个 PR 中,我把所有interface
s都改成了type
s,因为 s 的数量已经超过了type
s 。在审核中,我被要求撤销这个更改。我照做了,但我也想知道和interface
之间到底有什么区别。让我们来弄清楚这个问题。我在本文中使用最新的 TS (v3.5.1) 作为示例。interface
type
相似之处
记录
interface IAnimal {
name: string;
}
type Animal = {
name: string;
};
泛型
interface IAnimal<P = string> {
name: P;
}
type Animal<P = string> = {
name: P;
};
交叉路口
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;
implements
class Dog implements IAnimal {
name: string = "good dog";
}
class Cat implements Animal {
name: string = "Where is my food, human?";
}
扩展类
class Control {
private state: any;
}
interface ISelectableControl extends Control {
select(): void;
}
type SelectableControl = Control & {
select: () => void;
};
功能
type Bark = (x: Animal) => void;
interface iBark {
(x: Animal): void;
}
和泛型:
type Bark = <P = Animal>(x: P) => void;
interface iBark {
<P = Animal>(x: P): void;
}
递归声明
type Tree<P> = {
node: P;
leafs: Tree<P>[];
};
interface ITree<P> {
node: P;
leafs: ITree<P>[];
}
精确的
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'.
可转位
type StringRecord = {
[index: string]: number;
};
interface IStringRecord {
[index: string]: number;
}
差异
原始类型
您只能使用类型来为原始类型添加别名
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;
元组
不能用接口声明元组
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
不相交联合
不相交联合仅适用于以下类型:
type DomesticAnimals = { type: "Dog" } | { type: "Cat" };
并且不能使用不相交的联合类型extends
interface IDomesticAnimals extends DomesticAnimals {}
// An interface can only extend an object type or intersection of object types with statically known members
new
您可以声明new
interface IClassyAnimal {
new (name: string);
}
它没有像你期望的那样工作
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'.
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'.
每个范围只有一个声明
每个范围只能声明一次类型
type Once = { a: string };
type Once = { b: string };
// Duplicate identifier 'Once'.
您可以在每个范围内多次声明接口(最终结果将是所有声明的总和)
interface IOnce {
a: string;
}
interface IOnce {
b: string;
}
实用程序类型
大多数情况下,你会使用类型而不是接口来创建实用程序类型,例如:
export type NonUndefined<A> = A extends undefined ? never : A;
结论
在早期版本的 TS 中,并非所有这些功能都可行,所以人们习惯了使用接口。但在最新版本的 TS 中,类型似乎更加强大,我们随时都可以使用它们🤔。还是我漏掉了什么?
TS 中有很多细微差别——有些东西可能在小示例中有效(我演示过),但在大示例中就不行了。如果我漏掉了什么,请指正。
文章来源:https://dev.to/stereobooster/typescript-type-vs-interface-2n0c