声明合并

  • 概念引入
  • 合并接口


概念引入

“声明合并”是指编译器将针对同一个名字的两个独立声明合并为单一声明。 合并后的声明同时拥有原先两个声明的特性。 任何数量的声明都可被合并;不局限于两个声明

interface Box23 {
  height: number;
  width: number;
}
interface Box23 {
  scale: number;
}
let box: Box23 = {height: 5, width: 6, scale: 10};

上述虽然不会报错,但是不太美观

interface Box23 {
  scale: number;
  height: number;
  width: number;
}

合并接口

最简单也最常见的声明合并类型是接口合并。 从根本上说,合并的机制是把双方的成员放到一个同名的接口里

1、相同接口,同时声明了同名的非函数成员且它们的类型不同,则编译器会报错相同接口,的非函数的成员应该是唯一的,如果它们不是唯一的,那么它们必须是相同的类型

interface Box23 {
  height: number;
  width: number;
}

interface Box23 {
  scale: number;
  width: string
}
// Subsequent property declarations must have the same type.  Property 'width' must be of type 'number', but here has type 'string'.     
// 随后的属性声明必须具有相同的类型。属性'width'必须是'number'类型,但这里有'string'类型。

2、函数中的接口合并

对于函数成员,每个同名函数声明都会被当成这个函数的一个重载。 同时需要注意,当接口 A与后来的接口 A合并时,后面的接口具有更高的优先级

函数重载回顾一下:

function reverse(x: number): number;
function reverse(x: string): string;
function reverse(x: number | string): number | string {
    if (typeof x === 'number') {
        return Number(x.toString().split('').reverse().join(''));
    } else if (typeof x === 'string') {
        return x.split('').reverse().join('');
    }
}
interface Cloner {
    clone(animal: Animal): Animal;
}

interface Cloner {
    clone(animal: Sheep): Sheep;
}

interface Cloner {
    clone(animal: Dog): Dog;
    clone(animal: Cat): Cat;
}

//上述三个接口合并成一个声明
interface Cloner {
    clone(animal: Dog): Dog;
    clone(animal: Cat): Cat;
    clone(animal: Sheep): Sheep;
    clone(animal: Animal): Animal;
}

注意每组接口里的声明顺序保持不变,但各组接口之间的顺序是后来的接口重载出现在靠前位置。 这个规则有一个例外是当出现特殊的函数签名时。 如果签名里有一个参数的类型是 单一的字符串字面量(比如,不是字符串字面量的联合类型),那么它将会被提升到重载列表的最顶端。

interface Document {
    createElement(tagName: any): Element;
}
interface Document {
    createElement(tagName: "div"): HTMLDivElement;
    createElement(tagName: "span"): HTMLSpanElement;
}
interface Document {
    createElement(tagName: string): HTMLElement;
    createElement(tagName: "canvas"): HTMLCanvasElement;
}

//合并后
interface Document {
    createElement(tagName: "canvas"): HTMLCanvasElement;
    createElement(tagName: "div"): HTMLDivElement;
    createElement(tagName: "span"): HTMLSpanElement;
    createElement(tagName: string): HTMLElement;
    createElement(tagName: any): Element;
}