TS merges multiple type declarations of the same name into a type type structure

The TS declaration creates an entity containing the namespace, type, and value. The namespace creation declaration creates a namespace, which can be specified by the. Symbolic access. The type creation declaration creates a type with a specific “shape” and binds it to a specific name. Finally, the value creation declaration creates values that are visible in the JS file.

Understanding what each declaration creates can help understand the declaration merge behavior.

What is indicated in the figure below is to declare that type A is (simultaneously) one or more of the namespaces/types/values.

Combined interface

For non-function members, interfere with the same name will integrate all members, and TS will report an error if the interface with the same name has a different type.

interface Box{
    height: number;
    width: number
}

interface Box{
    scale: number
}

let box: Box = {height: 5, width: 6, scale: 10}

interface a{
    name: string
}
intreface a{
    // crash
    name: number    
}
Copy the code

For function members, there is an overload effect because functions with the same name have different types. Later declared functions have a higher priority.

interface Cloner{ clone(animal: Animal): Animal } interface Cloner{ clone(animal: Sheep): Interface Cloner{clone(animal: Sheep): Sheep; clone(animal: Animal): Animal }Copy the code

However, there is a special case, if the parameter is the type of a single string, such as params: “a” (not a string type of joint type, “a” | “b”), then this function will be up to the top.

interface Document{ createElement(tagName: any): Element; } interface Document{ createElement(tagName: "div"): HTMLDivElement; } interface Document {createElement method (tagName: "div" | "a") : Element} / / equivalent interface Document {createElement method (tagName: "div"): HTMLDivElement; createElement(tagName: "div"|"a"):Element; createElement(tagName: any):Element; }Copy the code

Merge namespaces

Merge namespaces: Interfaces exported from the same namespace are automatically merged according to the preceding rules, resulting in one merged interface per namespace

Merge of namespace values: If two namespaces are identical, the exported members of the second namespace are added to the first namespace. Two identical namespaces with different exported members can be accessed in either namespace.

Note: Must be export member

namespace Animals{
    export class Zebra{}
    // work
    let a:Legged
    // crash
    let c:Dog
}

namespace Animals{
    export interface Legged{
        numberOfLegs: number
    }
    class Dog{}
    // work
    let b:Zebra
}
Copy the code

Use of namespaces

Use the “.” You can access exported types and values in the namespace.

class Album{
    label: Album.AmbulLabel
}
namespace Album{
    export class AlbumLabel {}
}

function buildLabel(name: string): string{
    return buildLabel.prefix + name + buildLable.suffix
}
namespace buildLabel{
    export let suffix = "";
    export let prefix = "Hello. ";
}

enum Color{
    red = 1,
    green = 2,
    blue = 4,
}

namespace Color{
    export fucntion mixColor(colorName: string){
        if(colorName == "yellow"){
            return Color.red + Color.green
        }
    }
}
Copy the code

Uncoalescing part

Classes cannot merge with other classes or variables.

For more information, see Blending.

Module Augmentation

JS modules do not support merging. But you can do something like “merge” by importing and updating existing objects

// observalb.ts
export class Observable<T>{
    // ... implementation
}

// map.ts
import { Observable } from "./observable"
Observable.prototype.map = function (f){
    // implement
}
Copy the code

declare module

Note the import method import “./map” below. In this case, import does nothing. But math.h ts in the code will be specified to have side effects (www.typescriptlang.org/docs/handbo…

// observable.ts
export class Observable<T>{
    // ...
}


// map.ts
import { Observable } from "./observable";
declare module "./observable" {
    interface Observable<T> {
        map<U>(f: (X: T) => U): Observable<U>
    }
}
Observable.prototype.map = function (f){
    // ...
}


// consumer.ts
import { Observable } from "./observable";

import "./map";
let o: Observable<number>
o.map(x => x.toFixed())
Copy the code

Global Augmentation

export class Observable<T>{
    // implement
}

declare global {
    interface Array<T> {
        toObservable(): Observable<T>
    }
}

Array.prototype.toObservable = function (){
    // ...
}
Copy the code

reference

www.typescriptlang.org/docs/handbo…