TypeScript 中的接口声明合并

在我们的 前一篇关于TypeScript Mixins的帖子中,我们简短地谈到了TypeScript中的声明合并,在这些帖子系列中,我们将从与界面声明合并的界面开始深入一点。

什么是声明合并?

声明合并是当TypeScript编译器将两个或多个类型合并为一个声明时,只要它们具有相同的名称。

TypeScript 允许多种类型的合并,如界面界面,enumenum,namespacenamespace等。

让我们从界面界面合并开始,看看一个例子:

 1interface Person {
 2  name: string;
 3}
 4
 5interface Person {
 6  age: number;
 7}
 8
 9interface Person {
10  height: number;
11}
12
13class Employee implements Person {
14  name = "Mensah"
15  age = 100;
16  height = 40
17}
18
19const employee = new Employee();
20console.log(employee) // {name: "Mensah", age: 100, height: 40}

由于所有界面都被声明为同名,因此它们被合并为一个定义,因此员工类包含所有界面的属性。

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

如果将合并的任何接口都包含相同的属性名称,而该属性不是函数,那么属性的类型必须是相同的,否则编译器会引发错误。

 1interface Person {
 2  name: string;
 3  zipCode: string;
 4}
 5
 6interface Person {
 7  age: number;
 8  zipCode: string; // acceptable
 9}
10
11interface Person {
12   zipCode: number; // error
13}

界面上相同的属性名称(功能)

当合并界面中的元素是函数,并且它们具有相同的名称时,它们会被过载,也就是说,取决于通过的参数的类型,将调用相应的函数。

 1interface Person {
 2  speak(words: string);
 3}
 4
 5interface Person {
 6  speak(words: number);
 7}
 8
 9const person: Person = {
10  speak: (wordsOrNum) => wordsOrNum
11}
12
13console.log(person.speak("Hi")) // speak(words: string) is used
14console.log(person.speak(2)) // speak(words: number) is used

当包含相同签名函数的接口合并时,最后宣布的接口中的函数出现在合并接口的顶部,第一个接口中宣布的函数出现在下方。

 1interface Person {
 2  speak(words:string);
 3}
 4
 5interface Person {
 6  speak(words: any);
 7}
 8
 9interface Person {
10  speak(words: number);
11  speak(words: boolean);
12}
13
14// This is how the final merged interface looks like
15interface Person {
16  // functions in the last interface appear at the top
17  speak(words: number);
18  speak(words: boolean);
19
20  // function in the middle interface appears next
21  speak(words: any):number;
22
23  // function in the first interface appears last
24  speak(words: string):string;
25}

因此,在我们上面的例子中,‘speak(words: string)’永远不会被调用,因为在最终合并的‘Person’接口中,‘speak(words: any):number’在‘speak(words: string):string’之前出现,并且由于‘any’可以代表任何类型,即使一个‘string’被传递为‘argument’,它也会被调用。

为了证明这一点,当您在下面的代码中横跨per变量时,它会显示const per:number,而不是const per: string,即使我们正在通过一个字符串参数。

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

这适用于所有接口 expect,当相同名称函数参数具有字母字符串(https://andsky.com/tech/tutorials/typescript-string-literal-types)作为类型。它遵循上述相同的顺序,但具有字母字符串类型的函数具有更高的优先级,因此出现在顶部。

值得注意的是,后续界面中的字符串字母会像上面解释的那样出现在初始界面之前。

 1interface Person {
 2  speak(words: number);
 3  speak(words: "World!"); // string literal type
 4}
 5
 6interface Person {
 7  speak(words: "Hello"); // string literal type
 8}
 9
10interface Person {
11  speak(words: string);
12}
13
14// merged interface output.
15interface Person {
16  // string literals are given precedence
17  speak(words: "Hello");
18  speak(words: "World!");
19
20  // the rest of the functions are arranged using the same rules.
21  speak(words: string);
22  speak(words: number);
23}

希望有用!希望有用!

Published At
Categories with 技术
Tagged with
comments powered by Disqus