比较 Type 与 Interface 在使用时的相似和不同。
# 相似处
# 定义
interface IAnimal {
name: string;
}
type Animal = {
name: string;
};
1
2
3
4
5
6
7
2
3
4
5
6
7
# 泛型
interface IAnimal<P = string> {
name: P;
}
type Animal<P = string> = {
name: P;
};
1
2
3
4
5
6
7
2
3
4
5
6
7
# 合并
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;
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
# 实现
class Dog implements IAnimal {
name: string = "good dog";
}
class Cat implements Animal {
name: string = "Where is my food, human?";
}
1
2
3
4
5
6
7
2
3
4
5
6
7
# 继承类
class Control {
private state: any;
}
interface ISelectableControl extends Control {
select(): void;
}
type SelectableControl = Control & {
select: () => void;
};
1
2
3
4
5
6
7
8
9
10
11
2
3
4
5
6
7
8
9
10
11
# 定义函数
type Bark = (x: Animal) => void;
interface iBark {
(x: Animal): void;
}
// 使用泛型
type Bark = <P = Animal>(x: P) => void;
interface iBark {
<P = Animal>(x: P): void;
}
1
2
3
4
5
6
7
8
9
10
11
12
2
3
4
5
6
7
8
9
10
11
12
# 递归定义
type Tree<P> = {
node: P;
leafs: Tree<P>[];
};
interface ITree<P> {
node: P;
leafs: ITree<P>[];
}
1
2
3
4
5
6
7
8
9
2
3
4
5
6
7
8
9
# 精确(形状保持一致)
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'.
1
2
3
4
5
6
7
8
9
2
3
4
5
6
7
8
9
# 任意属性
type StringRecord = {
[index: string]: number;
};
interface IStringRecord {
[index: string]: number;
}
1
2
3
4
5
6
7
2
3
4
5
6
7
# 不同处
# 原始数据类型
你只能用 Type 来给原始数据类型取别名。
type NewNumber = number;
interface INewNumber extends number {}
// 'number' only refers to a type, but is being used as a value here.
// 可以继承 Number
interface INewNumber extends Number {}
// 但是别忘了 1 instanceof Number === false
1
2
3
4
5
6
7
8
2
3
4
5
6
7
8
# 元祖
不能用 Interface 声明元祖。
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
1
2
3
4
5
6
7
8
9
10
2
3
4
5
6
7
8
9
10
# 联合类型
只有 Type 能使用联合类型。
type DomesticAnimals = { type: "Dog" } | { type: "Cat" };
1
联合类型不能与 extends
一起使用。
interface IDomesticAnimals extends DomesticAnimals {}
// An interface can only extend an object type or intersection of object types with statically known members
1
2
2
# new
你可以声明 new
的类型
interface IClassyAnimal {
new (name: string);
}
1
2
3
2
3
但是不会像你预期那样工作
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'.
1
2
3
4
5
6
7
8
2
3
4
5
6
7
8
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'.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
2
3
4
5
6
7
8
9
10
11
12
13
14
# 在作用域中声明多次
每个作用域内只能声明一次 Type。
type Once = { a: string };
type Once = { b: string };
// Duplicate identifier 'Once'.
1
2
3
2
3
可以声明多次 Interface(结果会合并所有的声明)。
interface IOnce {
a: string;
}
interface IOnce {
b: string;
}
1
2
3
4
5
6
2
3
4
5
6
# 实用类型
大多数情况下,你会使用 Type 而不是 Interface 来创建实用类型。
export type NonUndefined<A> = A extends undefined ? never : A;
1
# 结尾
在早期的TS版本中,大家习惯了 Interface。但在最新版本的TS,似乎 Type 有着更强大的能力。在 TS 中有很多细微的差别,有些例子可能适合 Interface,但有些情况可能 Type 会更合适,需要自己多做总结。