写点什么

TS 中 type 和 interface 在类型声明时的区别

作者:不叫猫先生
  • 2023-06-09
    北京
  • 本文字数:2283 字

    阅读完需:约 7 分钟

TS中type和interface在类型声明时的区别

在 TS 中interfacetype都可以用来自定义数据类型,两者有许多相同之处,但是也有差别。我们一般选择 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 定义了 namespeak 方法的 Animal 接口,然后使用 class 实现了该接口,并创建了一个 Dog 的实例,调用了speak方法。


type Animal = {  name: string;  speak: () => void;}
class Dog implements Animal { // 这里会报错,因为 Animal 是一个类型别名,不能被 class 实现}
复制代码


上述代码会在编译时报错,==<font color=red >因为 type 定义的 Animal 类型只是一个别名,并不是一个接口,不能被类实现。所以在需要定义一个可以被类实现的类型时,应该使用 interface 进行定义。</font>==

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)多接口继承

==<font color=red >由于 type 只是类型别名,不能包含具体的属性和方法实现,因此它不支持通过 extends 关键字实现接口的继承。如果需要继承类型别名,需要使用交叉类型进行组合。</font>==


==<font color=red >当你需要让一个接口继承多个其他接口时,使用 interface 更加方便。因为 interface 允许你使用逗号分隔的方式来继承多个接口,而 type 只能使用交叉类型(&)来实现继承。</font>==


例如:


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,};
复制代码


在上面的例子中,我们定义了三个接口:PersonEmployee ManagerManager 接口继承了 PersonEmployee 接口,以及自己的属性 teamSize。如果使用 type 来定义 Manager 类型,那么就需要使用交叉类型来实现继承,但是这么实现起来就比较复杂。


总的来说,interface 和 type 都有自己的优势和使用场景。在 TypeScript 3.7 版本之后,type 也可以实现声明合并和继承多个类型的功能,因此在选择使用 interface 还是 type 时,应该根据具体情况来决定。

4.interface 可以定义多个同名接口并合并,而 type 不支持

==<font color=red >当合并两个或多个具有相同名称的接口或类型时, interface 允许声明多个同名接口并将它们合并成一个。</font>== 例如:


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类型。


==<font color=red >interface 不支持使用typeof操作符获取实例的类型。因为interface只是一种接口定义,它本身不是一个值,无法获取其类型。</font>==

发布于: 刚刚阅读数: 4
用户头像

还未添加个人签名 2022-10-18 加入

前端领域优质创作者、阿里云专家博主,专注于前端各领域技术,共同学习共同进步,一起加油呀!

评论

发布
暂无评论
TS中type和interface在类型声明时的区别_6 月优质更文活动_不叫猫先生_InfoQ写作社区