您现在的位置是:首页 >学无止境 >【TypeScript】TS中type和interface在类型声明时的区别网站首页学无止境
【TypeScript】TS中type和interface在类型声明时的区别
🐱 个人主页:不叫猫先生
🙋♂️ 作者简介:2022年度博客之星前端领域TOP 2,前端领域优质作者、阿里云专家博主,专注于前端各领域技术,共同学习共同进步,一起加油呀!
💫优质专栏:vue3从入门到精通、TypeScript从入门到实践
📢 资料领取:前端进阶资料可以找我免费领取
🔥 摸鱼学习交流:我们的宗旨是在工作中摸鱼,摸鱼中进步,期待大佬一起来摸鱼(文末有我wx或者私信)。
目录
一、专栏介绍
TypeScript从入门到实践专栏是博主在学习和工作过程中的总结,实用性非常强,内容会不断进行精进,欢迎订阅哦,学会TS不迷路。
TS系列 | 标题 |
---|---|
基础篇 | TS入门(一) |
基础篇 | TS类型声明(二) |
基础篇 | TS接口类型(三) |
基础篇 | TS交叉类型&联合类型(四) |
基础篇 | TS类型断言(五) |
基础篇 | TS类型守卫(六) |
进阶篇 | TS函数重载(七) |
进阶篇 | TS泛型(八) |
进阶篇 | TS装饰器(九) |
进阶篇 | TS条件类型(十) |
进阶篇 | TS自定义类型之对象属性必选、对象属性可选 |
进阶篇 | TS中type和interface在类型声明时的区别 |
二、TS中type和interface在类型声明时的区别
在TS中interface
和 type
都可以用来自定义数据类型,两者有许多相同之处,但是也有差别。我们一般选择 type
来定义基本类型别名、联合类型、元组等类型,而选择 interface
来定义复杂的对象、类、以及进行接口的继承。
1. 声明常见类型
(1)定义基本类型
type Age = number;
interface Person {
name: string;
age: Age;
}
(2)定义函数类型
type Greeting = (name: string) => string;
interface Greeter {
(name: string): string;
}
(3)定义对象类型
type Point = { x: number; y: number };
interface Rectangle {
width: number;
height: number;
position: Point;
}
(4)定义泛型
type List<T> = {
data: T[];
add: (item: T) => void;
}
interface List<T> {
data: T[];
add: (item: T) => void;
}
interface
使用泛型的案例如下:
interface Container<T> {
value: T;
get(): T;
set(value: T): void;
}
class NumberContainer implements Container<number> {
value: number;
get() {
return this.value;
}
set(value: number) {
this.value = value;
}
}
const container = new NumberContainer();
container.set(42);
console.log(container.get()); //
2. interface 可以被类(class)实现(implement),而 type 不能
interface Animal {
name: string;
speak: () => void;
}
class Dog implements Animal {
name: string;
constructor(name: string) {
this.name = name;
}
speak() {
console.log("hello!");
}
}
const myDog = new Dog("Sparky");
myDog.speak(); // 输出 hello
上面代码使用interface
定义了 name
和 speak
方法的 Animal 接口,然后使用 class
实现了该接口,并创建了一个 Dog
的实例,调用了speak
方法。
type Animal = {
name: string;
speak: () => void;
}
class Dog implements Animal {
// 这里会报错,因为 Animal 是一个类型别名,不能被 class 实现
}
上述代码会在编译时报错,因为 type 定义的 Animal 类型只是一个别名,并不是一个接口,不能被类实现。所以在需要定义一个可以被类实现的类型时,应该使用 interface 进行定义。
3. interface 支持 extends 实现接口的继承,而 type 不支持
(1)单接口继承
interface Animal {
name: string;
speak: () => void;
}
interface Pet extends Animal {
owner: string;
play: () => void;
}
class Dog implements Pet {
name: string;
owner: string;
constructor(name: string, owner: string) {
this.name = name;
this.owner = owner;
}
speak() {
console.log("speak:hello");
}
play() {
console.log(`${this.name} is playing with ${this.owner}`);
}
}
const myDog = new Dog("myPet", "Mr.Cat");
myDog.speak(); // 输出 "speak:hello"
myDog.play(); // 输出 "myPet is playing with Mr.Cat"
(2)多接口继承
由于 type 只是类型别名,不能包含具体的属性和方法实现,因此它不支持通过 extends 关键字实现接口的继承。如果需要继承类型别名,需要使用交叉类型进行组合。
当你需要让一个接口继承多个其他接口时,使用 interface 更加方便。因为 interface 允许你使用逗号分隔的方式来继承多个接口,而 type 只能使用交叉类型(&)来实现继承。
例如:
interface Person {
name: string;
age: number;
}
interface Employee {
company: string;
jobTitle: string;
}
interface Manager extends Person, Employee {
teamSize: number;
}
const manager: Manager = {
name: 'John Doe',
age: 40,
company: 'ABC Inc.',
jobTitle: 'Manager',
teamSize: 10,
};
在上面的例子中,我们定义了三个接口:Person
、Employee
和 Manager
。Manager
接口继承了 Person
和 Employee
接口,以及自己的属性 teamSize
。如果使用 type 来定义 Manager
类型,那么就需要使用交叉类型来实现继承,但是这么实现起来就比较复杂。
总的来说,interface 和 type 都有自己的优势和使用场景。在 TypeScript 3.7 版本之后,type 也可以实现声明合并和继承多个类型的功能,因此在选择使用 interface 还是 type 时,应该根据具体情况来决定。
4.interface 可以定义多个同名接口并合并,而 type 不支持
当合并两个或多个具有相同名称的接口或类型时, interface 允许声明多个同名接口并将它们合并成一个。 例如:
interface User {
name: string;
age: number;
}
interface User {
gender: 'male' | 'female';
}
const user: User = {
name: '猫先生',
age: 25,
gender: 'male',
};
在上面的例子中,我们声明了两个同名的接口 User,并将它们合并成一个。如果使用 type 来定义 User 类型,那么就无法实现声明合并的功能,代码会直接报错。
5.type可以使用 typeof 获取实例的类型,而 interface 不支持
type Person = {
name: string;
age: number;
}
const john: Person = {
name: "John",
age: 30,
}
type PersonType = typeof john; // 类型为 { name: string, age: number }
在上图可以看到PersonType
类型和Person
类型一样,通过typeof
获取john
的数据类型,然后赋值给PersonType
类型。
interface
不支持使用typeof
操作符获取实例的类型。因为interface
只是一种接口定义,它本身不是一个值,无法获取其类型。