TypeScript中的Interface和Type:异同及使用场景

8/19/2021 Typescript

在TypeScript中,有两种用于定义自定义类型的主要方式:interface(接口)和type(类型)。它们看起来有些相似,但在某些方面有着不同的用途和特性。在本文中,我们将详细讨论这两者的异同以及它们在什么情况下应该使用。

# Interface(接口)

接口(interface) 主要用于定义对象的结构和形状,以及类与对象之间的契约。接口定义了一组属性和方法,对象或类必须遵循这个接口的契约。

interface User {
  name: string;
  age: number;
}

interface SetUser {
  (name: string, age: number): void;
}

Interface可以拓展(extends)其他接口,这意味着一个接口可以继承另一个接口的成员。

interface Name {
  name: string;
}

interface User extends Name {
  age: number;
}

Interface可以声明合并。如果多次声明同一个接口,它们会被合并成一个接口。

interface User {
  name: string;
  age: number;
}

interface User {
  sex: string;
}

/*
User 接口最终合并为:
{
  name: string;
  age: number;
  sex: string;
}
*/

Interface可以约束类的构造函数。接口可以用来约束一个类的构造函数,以确保类的实例满足接口定义的要求。

interface Counter {
    (start: number): string;
    interval: number;
    reset(): void;
}

function getCounter(): Counter {
    let counter = <Counter>function (start: number) { };
    counter.interval = 123;
    counter.reset = function () { };
    return counter;
}

# Type(类型)

类型(type) 主要用于定义自定义类型,可以表示基本类型别名、联合类型、元组等。

// 基本类型别名
type Name = string;

// 联合类型
type Pet = Dog | Cat;

// 具体定义数组每个位置的类型
type PetList = [Dog, Pet];

Type可以使用typeof获取实例的类型。这在需要获取某个变量的类型时非常有用。

let div = document.createElement('div');
type B = typeof div; // B的类型是HTMLDivElement

Type可以进行其他高级操作,如字符串字面量类型、模板字符串类型、条件类型等,用于创建更复杂的类型。

type StringOrNumber = string | number;
type Text = string | { text: string };
type NameLookup = Dictionary<string, Person>;
type Callback<T> = (data: T) => void;
type Pair<T> = [T, T];
type Coordinates = Pair<number>;
type Tree<T> = T | { left: Tree<T>, right: Tree<T> };

# Interface vs Type

# 共同点

  • 都可以描述对象或函数的结构。
  • 都可以被继承,或者通过交叉类型(Intersection Types)进行组合。
  • 都可以用来声明函数的属性。

# 不同点

Type可以声明基本类型别名、联合类型、元组等,而Interface不行。

// 基本类型别名
type Name = string

// 联合类型
interface Dog {
    wong();
}
interface Cat {
    miao();
}

type Pet = Dog | Cat

// 具体定义数组每个位置的类型
type PetList = [Dog, Pet]

// 还能通过typeof获取类型
let div = document.createElement('div');
type B = typeof div; // B的类型是HTMLDivElement

Interface可以约束类的构造函数,Type不行。

interface ClockConstructor {
    new (hour: number, minute: number): ClockConstructor; // 注意后面的 :ClockConstructor 
}

class Clock implements ClockConstructor {
    currentTime: Date;
    constructor(h: number, m: number) { }
}

Interface可以声明合并,多个相同名字的接口会被合并为一个。

interface User {
  name: string
  age: number
}

interface User {
  sex: string
}

/*
User 接口为 {
  name: string
  age: number
  sex: string 
}
*/

# 使用场景

  • 当您想要描述对象的形状以及类与对象之间的契约时,使用Interface更为合适。
  • 当您需要创建自定义类型别名、联合类型、元组等,使用Type更为适合。
  • 如果您不确定该使用哪个,或者只是希望定义一种类型而不是接口,那么应该使用Type。

最后,需要注意的是,TypeScript的发展和版本更新可能会影响这两者的功能和用法,因此建议查看最新的官方文档以获取最新信息。无论您选择使用哪种方式,都可以根据项目的需要来灵活选择,以编写出清晰、健壮且易维护的代码。