Copyright
Article reprinted from: HTTPS://GITHUB.COM/ZHONGSP
It is recommended that you jump directly to the URL above to see the latest version.
Introduced
Typescript has some unique concepts, either because we need to describe what has changed in the type of JavaScript top-level objects. One of these is called 声明合并 . Understanding this concept can be helpful for you to use Typescript to manipulate existing JavaScript. It also helps to understand the concepts of more advanced abstractions.
First, before we know how to make a declaration merge, let's take a look at what's called 声明合并 .
In this manual, declaration merging means that the compiler merges two declarations of the same name into a single declaration. The combined declaration has the attributes of the two merged declarations. The declaration is not limited to merging only two, any number can be.
Basic concepts
The declaration in typescript creates one of the following three entities: namespace, type, or value. The declaration used to create a namespace creates a new namespace: it contains some names that can be accessed with the (.) symbol. The declaration used to create the type is done by creating a type with the given name and structure. Finally, the declaration of creating a value is the part that can be seen in the generated JavaScript (for example, functions and variables).
| Declaration Type |
Namespace |
Type |
Value |
| Namespace |
X |
|
X |
| Class |
|
X |
X |
| Interface |
|
X |
|
| Function |
|
|
X |
| Variable |
|
|
X |
Understanding what each claim creates helps to understand what is being merged when the declaration is merged.
It is understood that each declaration corresponds to what is created for understanding if it is helpful to make a declaration merge.
Merging interfaces
The simplest and most common is the merge interface, which declares the kind of merge: interface merge. Fundamentally, the merging mechanism is to put the members of their declarations into a single interface of the same name.
interface Box { height: number; width: number;}interface Box { scale: number;}var box: Box = {height: 5, width: 6, scale: 10};
The members of an interface's non-function must be unique. If a non-function member with the same name is in multiple interfaces, an error is given.
For function members, each function declaration of the same name is treated as an overload of the function.
It is important to note that when interface a merges with interface a (which is called a ') behind it, the overloaded functions in a ' have higher precedence.
As shown in the following example:
interface Document { createElement(tagName: any): Element;}interface Document { createElement(tagName: string): HTMLElement;}interface Document { createElement(tagName: "div"): HTMLDivElement; createElement(tagName: "span"): HTMLSpanElement; createElement(tagName: "canvas"): HTMLCanvasElement;}
These three interfaces are combined into a single declaration. Note that the order of declarations in each set of interfaces remains the same, except that the back interface appears before the interface declaration in front of it.
interface Document { createElement(tagName: "div"): HTMLDivElement; createElement(tagName: "span"): HTMLSpanElement; createElement(tagName: "canvas"): HTMLCanvasElement; createElement(tagName: string): HTMLElement; createElement(tagName: any): Element;}
Merging namespaces
Similar to interfaces, namespaces with the same name also merge their members. Namespaces create namespaces and values, and we need to know how they all merge.
Namespaces are merged, and the module exports the same name interface, which forms a single namespace containing the merged interface.
Value, if the namespace of the given name is already present, then the exported member of the subsequent namespace is added to the existing module.
AnimalsTo declare a merge example:
namespace Animals { export class Zebra { }}namespace Animals { export interface Legged { numberOfLegs: number; } export class Dog { }}
Equivalent to:
namespace Animals { export interface Legged { numberOfLegs: number; } export class Zebra { } export class Dog { }}
In addition to these merges, you need to understand how non-exporting Members are handled. Non-exported members are visible only within the namespace in which they were originally stored (not merged). This means that after merging, members that are merged from other namespaces cannot access non-exported members.
The following example provides a clearer explanation:
namespace Animal { var haveMuscles = true; export function animalsHaveMuscles() { return haveMuscles; }}namespace Animal { export function doAnimalsHaveMuscles() { return haveMuscles; // <-- error, haveMuscles is not visible here }}
Because haveMuscles there is no export, only the animalsHaveMuscles function shares the original unincorporated namespace that can access the variable. doAnimalsHaveMusclesa function is part of a merged namespace, but cannot access non-exported members.
Namespaces are merged with classes and functions and enum types
Namespaces can be merged with other types of declarations. As long as the namespace definition conforms to the definition of the type that will be merged. The merge result contains the declaration type for both. Typescript uses this feature to implement some JavaScript design patterns.
First, try merging the namespaces and classes. This allows us to define inner classes.
class Album { label: Album.AlbumLabel;}namespace Album { export class AlbumLabel { }}
The merge rule is 合并命名空间 consistent with the rules in the section above, and we must export the class so that AlbumLabel the merged class can access it. The merge result is a class with an inner class. You can also use namespaces to add some static properties to a class.
In addition to the inner class pattern, you are in JavaScript and it is common to create a function to extend it later. Typescript uses a declaration merge to achieve this and to ensure type safety.
function buildLabel(name: string): string { return buildLabel.prefix + name + buildLabel.suffix;}namespace buildLabel { export var suffix = ""; export var prefix = "Hello, ";}alert(buildLabel("Sam Smith"));
Similarly, namespaces can be used to extend enumerated types:
Enum Color {red =1, green =2, blue =4}namespace Color {Exportfunction mixColor (colorname: string" {if (ColorName = "yellow") {return color.red + Color.green;} else if (colorname = "white") { Span class= "Hljs-keyword" >return color.red + color.green + color.blue; } else if (colorname = "magenta") { return color.red + Color.Blue;} else if (colorname = "cyan") { Span class= "Hljs-keyword" >return Color.green + color.blue; } }}
Illegal merger.
Not all merges are allowed. Now, a class cannot be merged with a class, a variable and a type cannot be merged, and an interface cannot be merged with a class. To emulate the merging of classes, refer to Mixins in TypeScript.
Reprint: "TypeScript Chinese Introductory Course" 11, Declaration merger