TypeScript中的接口声明合并

来自菜鸟教程
跳转至:导航、​搜索

在我们的 上一篇关于 TypeScript Mixins 的文章中,我们简要讨论了 TypeScript 中的声明合并。 在这一系列文章中,我们将从接口声明合并的接口开始更深入一些。

什么是声明合并?

声明合并是 TypeScript 编译器将两个或多个类型合并到一个声明中,前提是它们具有相同的名称。

TypeScript 允许在多种类型之间进行合并,例如 interfaceinterfaceenumenumnamespacenamespace、等等 一个值得注意的不允许合并是 classclass 合并。 如果您想要这样的功能,请查看 mixins

让我们通过查看一个示例开始使用 interfaceinterface 合并:

interface Person {
  name: string;
}

interface Person {
  age: number;
}

interface Person {
  height: number;
}

class Employee implements Person {
  name = "Mensah"
  age = 100;
  height = 40
}

const employee = new Employee();
console.log(employee) // {name: "Mensah", age: 100, height: 40}

由于所有接口都使用相同的名称 Person 声明,因此它们被合并到一个定义中,因此 Employee 类包含来自所有接口的属性。

接口中的相同属性名称(非函数)

如果要合并的任何接口包含相同的属性名称并且该属性不是函数,则属性的 type 必须相同,否则编译器将抛出错误。

interface Person {
  name: string;
  zipCode: string;
}

interface Person {
  age: number;
  zipCode: string; // acceptable
}

interface Person {
   zipCode: number; // error
}

接口(函数)中的相同属性名称

当合并的接口中的元素是函数并且它们具有相同的名称时,它们被重载,即根据传递的参数的type,将调用相应的函数。

interface Person {
  speak(words: string);
}

interface Person {
  speak(words: number);
}

const person: Person = {
  speak: (wordsOrNum) => wordsOrNum
}

console.log(person.speak("Hi")) // speak(words: string) is used
console.log(person.speak(2)) // speak(words: number) is used

当包含相同签名函数的接口被合并时,最后声明的接口中的函数出现在合并接口的顶部,而第一个接口中声明的函数出现在下面。

interface Person {
  speak(words:string);
}

interface Person {
  speak(words: any);
}

interface Person {
  speak(words: number);
  speak(words: boolean);
}

// This is how the final merged interface looks like
interface Person {
  // functions in the last interface appear at the top
  speak(words: number);
  speak(words: boolean);

  // function in the middle interface appears next
  speak(words: any):number;

  // function in the first interface appears last
  speak(words: string):string;
}

这样做的原因是,后来声明的接口比最初声明的接口具有更高的优先级。 所以在我们上面的例子中,speak(words: string) 永远不会被调用,因为在最终合并的 Person 接口中,speak(words: any):number 出现在 speak(words: string):string 之前并且因为 [X152X ] 可以代表任何类型,即使 string 作为 argument 传递,它也会被调用。

为了证明这一点,当您将鼠标悬停在下面代码中的 per 变量上时,它会显示 const per: number 而不是 const per: string 即使我们传入 [X157X ] 争论。

const per = person.speak("bacon");

当同名函数参数具有 字符串文字 作为 type 时,所有接口 expect 都是如此。 它遵循上述相同的顺序,但具有字符串文字类型的函数具有更高的优先级,因此出现在顶部。

值得注意的是,后面的接口中的字符串文字会出现在上面解释的初始接口之前。

interface Person {
  speak(words: number);
  speak(words: "World!"); // string literal type
}

interface Person {
  speak(words: "Hello"); // string literal type
}

interface Person {
  speak(words: string);
}


// merged interface output.
interface Person {
  // string literals are given precedence
  speak(words: "Hello");
  speak(words: "World!");

  // the rest of the functions are arranged using the same rules.
  speak(words: string);
  speak(words: number);
}

就是这样。 希望这很有用。 😊😎