3
头图

TypeScript 是 JavaScript 的一个超集,通过为 JavaScript 提供类型系统和其他语言特性来增强 JavaScript 的功能(配合VSCode,代码提示真的丝滑)。TypeScript 可以在编译时进行类型检查,从而提供更好的代码可读性和可维护性,并且可以在开发过程中减少错误和调试时间),减少了很多低级语法错误,这类问题有时候排查好久才会发现,查到的时候往往会忍不住骂娘。

我使用TypeScript的时长差不多两年半了,在使用的初期,我便注意到在 TypeScript 中,interface 和 type 都可以用来定义对象的类型。

// 使用 interface 定义对象类型
interface User {
  name: string;
  age: number;
}

// 使用 type 定义对象类型
type User = {
  name: string;
  age: number;
}

上面定义的两个User对象类型,效果是等效的,在声明对象类型,函数的参数和返回类型等最常用的场景中使用起来效果没有任何差别。

但是二者的使用方式其实还是有挺多区别,花几分钟了解之后,还是可以在小白面前装一下的。

哈哈,玩笑玩笑,最终还是为了更好地使用工具。

总结起来包括了6点,TypeScript的官方文档中也有部分描述,点击末尾原文链接可以跳转官方文档(这里提一句,TS的官方文档写得真好,强烈建议读英文原版文档,一开始可能有点慢,但是很快就适应过来了)。

## 1. interface 可以被类实现和扩展,而 type 不行 (感谢aimerfan同学指出,在TS Playground跑了一下,确实无编译报错,故删除这点)

下面的例子中,用interface声明了Animal,用type声明了Animal2,当我试图实现(implements)Animal2的时候,就报错了。


interface Animal {
  name: string;
  eat(): void;
}

type Animal2 = {
  name: string;
  eat(): void;
}

class Cat implements Animal {
  name: string;
  constructor(name: string) {
    this.name = name;
  }
  eat() {
    console.log(`${this.name} is eating.`);
  }
}
// 错啦,type定义的对象类型不能被实现
class Dog implements Animal2 {
  name: string;
  constructor(name: string) {
    this.name = name;
  }
  eat() {
    console.log(`${this.name} is eating.`);
  }
}

interface就是用来实现的,就像信任就是用来辜负的一样。

2. 同名interface 可以被合并,而 type 不行。

在同一作用域内定义了两个相同名称的 interface,TypeScript 会将它们合并为一个。但是如果定义了两个相同名称的 type,则会产生命名冲突错误。


interface A {
  name: string;
}

interface A {
  age: number;
}

// A 接口被合并为 { name: string; age: number; }
const a: A = {
  name: 'Jack',
  age: 20
}

// Error: Duplicate identifier 'B'.
type B = {
  name: string;
}

type B = {
  age: number;
}

3. type可以用于声明组合类型和交叉类型,interface则不行

下面这个case就是用type声明了组合类型和交叉类型。

interface InterfaceA {
  key1: string;
}

interface InterfaceB {
  key2: number;
}

type UnionType = InterfaceA | InterfaceB;
type IntersectionType = InterfaceA & InterfaceB;

const obj1: UnionType = { key1: 'hello' }; // 符合 InterfaceA
const obj2: UnionType = { key2: 42 }; // 符合 InterfaceB
const obj: IntersectionType = { key1: 'hello', key2: 42 }; // 同时符合 InterfaceA 和 InterfaceB

4. type声明的对象类型可以拿来组合成新的对象类型,interface不行

type Animal = {
  name: string
}

type Bear = Animal & { 
  honey: boolean 
}

const bear = getBear();
bear.name;
bear.honey;

5. 在定义对象类型时,interface 和 type 的语法略有不同。interface 使用花括号 {},而 type 使用等号 =。

这点有点凑数,但是确实是新手日常写代码经常混淆的点

// interface 使用花括号 {} 定义对象类型
interface User {
  name: string;
  age: number;
}
// type 使用等号 = 定义对象类型
type User = {
  name: string;
  age: number;
}

6. type可以给基本类型起别名,interface不行


type StringTypeHAHAHHAHA = string;
// interface做不到

——分割线————————————————

列举出来一看,差别还是挺多的,但是这些点其实没有必要去记忆,因为TypeScript的工具链相当完善,不合适的用法编辑器都会有清晰的提示。

在实际应用中,除了功能性的刚性约束,更重要的是用类型去表达一个准确的语义,事实上许多复杂类型需要组合使用type和interface才能实现。

本文权当做了一个趣味探索,有其他关于TypeScript好玩的点,欢迎留言交流。


方始终
999 声望47 粉丝

web developer.