TypeScript 3.1 namespace namespace

Links to the original text: http://www.ptbird.cn/typescript-namespace.html

TypeScript 3.1 namespace namespace

Comments:0 · Reading: 808 · Like: 0

 

 

Naming Note: The term name has changed in TypeScript 1.5. "Internal module" is now called "namespace" and "external module" is now abbreviated as "module" in order to be consistent with ES6 terminology, that is, module X {equivalent to the current namespace X{

Provide basic articles and code examples

The following code will be used throughout the article, mainly a few simple string validators, which can be used to validate user input in the form or to validate external data:

All validators are placed in one file:

// All validators are in one file

interface StringValidator {
    isAcceptable(s: string): boolean;
}

let lettersRegexp = /^[A-Za-z]+$/;
let numberRegexp = /^[0-9]+$/;

class LettersOnlyValidator implements StringValidator {
    isAcceptable(s: string) {
        return lettersRegexp.test(s);
    }
}

class ZipCodeValidator implements StringValidator {
    isAcceptable(s: string) {
        return s.length === 5 && numberRegexp.test(s);
    }
}

// Some simple tests

let strings = ["Hello", "8288", "123"];

let validators: { [s: string]: StringValidator; } = {};

validators['ZIP code'] = new ZipCodeValidator();
validators['Letters only'] = new LettersOnlyValidator();

for (let s of strings) {
    for (let name in validators) {
        let isMatch = validators[name].isAcceptable(s);
        console.log(`'${ s }' ${ isMatch ? "matches" : "does not match" } '${ name }'.`);
    }
}

The results of compiler compilation are as follows:

// All validators are in one file
var lettersRegexp = /^[A-Za-z]+$/;
var numberRegexp = /^[0-9]+$/;
var LettersOnlyValidator = /** @class */ (function () {
    function LettersOnlyValidator() {
    }
    LettersOnlyValidator.prototype.isAcceptable = function (s) {
        return lettersRegexp.test(s);
    };
    return LettersOnlyValidator;
}());
var ZipCodeValidator = /** @class */ (function () {
    function ZipCodeValidator() {
    }
    ZipCodeValidator.prototype.isAcceptable = function (s) {
        return s.length === 5 && numberRegexp.test(s);
    };
    return ZipCodeValidator;
}());
// Some simple tests
var strings = ["Hello", "8288", "123"];
var validators = {};
validators['ZIP code'] = new ZipCodeValidator();
validators['Letters only'] = new LettersOnlyValidator();
for (var _i = 0, strings_1 = strings; _i < strings_1.length; _i++) {
    var s = strings_1[_i];
    for (var name_1 in validators) {
        var isMatch = validators[name_1].isAcceptable(s);
        console.log("'" + s + "' " + (isMatch ? "matches" : "does not match") + " '" + name_1 + "'.");
    }
}

Operation results:

Namespaces

There are only two validators above. With the increase of validators, we need a way to organize the code so that we can record their types without worrying about naming conflicts with other objects. Therefore, we wrap validators in a namespace instead of putting them in a global namespace.

In the following example, all validator-related types are placed in a namespace called Validation, because we want these interfaces and classes to be accessible outside the namespace, so we need to use export.

Conversely, variables lettersRegexp and numberRegexp do not need to be exported in detail, so they are not accessible outside the namespace. In the test code at the end of the file, it's better than accessing outside the namespace, so you need to qualify the name of the type, such as Validator. Letters OnlyValidator.

Verifier using namespaces

// Verifier using namespaces

namespace Validator {
    export interface StringValidator {
        isAcceptable(s: string): boolean;
    }

    const lettersRegexp = /^[A-Za-z]+$/;
    const numberRegexp = /^[0-9]+$/;

    export class LettersOnlyValidator implements StringValidator {
        isAcceptable(s: string) {
            return lettersRegexp.test(s);
        }
    }

    export class ZipCodeValidator implements StringValidator {
        isAcceptable(s: string) {
            return lettersRegexp.test(s);
        }
    }

}

// test

let strings = ['Hello', '89772', '1230'];

let validators: { [s: string]: Validator.StringValidator; } = {};

validators['ZIP code'] = new Validator.ZipCodeValidator();
validators['Letters Only'] = new Validator.LettersOnlyValidator();

for (let s of string) {
    for (let name in validators) {
        console.log(`"${ s }" - ${ validators[name].isAcceptable(s) ? "matches" : "does not match" } ${ name }`);
    }
}

Compiled results:

// Verifier using namespaces
var Validator;
(function (Validator) {
    var lettersRegexp = /^[A-Za-z]+$/;
    var numberRegexp = /^[0-9]+$/;
    var LettersOnlyValidator = /** @class */ (function () {
        function LettersOnlyValidator() {
        }
        LettersOnlyValidator.prototype.isAcceptable = function (s) {
            return lettersRegexp.test(s);
        };
        return LettersOnlyValidator;
    }());
    Validator.LettersOnlyValidator = LettersOnlyValidator;
    var ZipCodeValidator = /** @class */ (function () {
        function ZipCodeValidator() {
        }
        ZipCodeValidator.prototype.isAcceptable = function (s) {
            return lettersRegexp.test(s);
        };
        return ZipCodeValidator;
    }());
    Validator.ZipCodeValidator = ZipCodeValidator;
})(Validator || (Validator = {}));
// test
var strings = ['Hello', '89772', '1230'];
var validators = {};
validators['ZIP code'] = new Validator.ZipCodeValidator();
validators['Letters Only'] = new Validator.LettersOnlyValidator();
for (var _i = 0, string_1 = string; _i < string_1.length; _i++) {
    var s = string_1[_i];
    for (var name_1 in validators) {
        console.log("\"" + s + "\" - " + (validators[name_1].isAcceptable(s) ? "matches" : "does not match") + " " + name_1);
    }
}

You can see that after using NameSpace, Validator actually assigns two properties through an immediate execution function.

Separation into multiple files

As applications grow larger and larger. We need to separate the code into different files for easy maintenance.

Multi-file namespace

Now divide the above Validator into multiple files, although they are different files, but they are still the same namespace and are used as if they were the top one in a file.

Because there are dependencies between different files, a reference tag is added to tell the compiler the association between files.

validation.ts

namespace Validation {
    export interface StringValidator {
        isAcceptable(s: string): boolean;
    }
}

LettersOnlyValidator.ts

/// <reference path="Validation.ts" />
namespace Validation {
    const lettersRegexp = /^[A-Za-z]+$/;
    export class LettersOnlyValidator implements StringValidator {
        isAcceptable(s: string) {
            return lettersRegexp.test(s);
        }
    }
}

ZipCodeVlidator.ts:

/// <reference path="Validation.ts" />
namespace Validation {
    const numberRegexp = /^[0-9]+$/;
    export class ZipCodeValidator implements StringValidator {
        isAcceptable(s: string) {
            return s.length === 5 && numberRegexp.test(s);
        }
    }
}

Test.ts

/// <reference path="Validation.ts" />
/// <reference path="LettersOnlyValidator.ts" />
/// <reference path="ZipCodeValidator.ts" />

// Some samples to try
let strings = ["Hello", "98052", "101"];

// Validators to use
let validators: { [s: string]: Validation.StringValidator; } = {};
validators["ZIP code"] = new Validation.ZipCodeValidator();
validators["Letters only"] = new Validation.LettersOnlyValidator();

// Show whether each string passed each validator
for (let s of strings) {
    for (let name in validators) {
        console.log(`"${ s }" - ${ validators[name].isAcceptable(s) ? "matches" : "does not match" } ${ name }`);
    }
}

When it comes to multiple files, you have to ensure that all compiled code is loaded in two ways:

The first way to compile all input files into one output file is to use the -- outFile tag

tsc --outFile sample.js Test.ts

Compiled results:

/// <reference path="Validation.ts" />
var Validation;
(function (Validation) {
    var lettersRegexp = /^[A-Za-z]+$/;
    var LettersOnlyValidator = /** @class */ (function () {
        function LettersOnlyValidator() {
        }
        LettersOnlyValidator.prototype.isAcceptable = function (s) {
            return lettersRegexp.test(s);
        };
        return LettersOnlyValidator;
    }());
    Validation.LettersOnlyValidator = LettersOnlyValidator;
})(Validation || (Validation = {}));
/// <reference path="Validation.ts" />
var Validation;
(function (Validation) {
    var numberRegexp = /^[0-9]+$/;
    var ZipCodeValidator = /** @class */ (function () {
        function ZipCodeValidator() {
        }
        ZipCodeValidator.prototype.isAcceptable = function (s) {
            return s.length === 5 && numberRegexp.test(s);
        };
        return ZipCodeValidator;
    }());
    Validation.ZipCodeValidator = ZipCodeValidator;
})(Validation || (Validation = {}));
/// <reference path="Validation.ts" />
/// <reference path="LettersOnlyValidator.ts" />
/// <reference path="ZipCodeValidator.ts" />
// Some samples to try
var strings = ["Hello", "98052", "101"];
// Validators to use
var validators = {};
validators["ZIP code"] = new Validation.ZipCodeValidator();
validators["Letters only"] = new Validation.LettersOnlyValidator();
// Show whether each string passed each validator
for (var _i = 0, strings_1 = strings; _i < strings_1.length; _i++) {
    var s = strings_1[_i];
    for (var name_1 in validators) {
        console.log("\"" + s + "\" - " + (validators[name_1].isAcceptable(s) ? "matches" : "does not match") + " " + name_1);
    }
}

The compiler automatically sorts the output according to the reference tags in the source code, or specifies each file separately.

tsc --outFile sample.js Validation.ts LettersOnlyValidator.ts ZipCodeValidator.ts Test.ts

Compiled results:

In the second way, you can compile every file (by default, see the screenshot above). Each source file will generate a JavaScript file, and then introduce all Javascript files in the correct order through the < script > tag on the page, such as:

 <script src="Validation.js" type="text/javascript" />
    <script src="LettersOnlyValidator.js" type="text/javascript" />
    <script src="ZipCodeValidator.js" type="text/javascript" />
    <script src="Test.js" type="text/javascript" />

IV. Aliases

Another simplified namespace operation is to use import q = x.y.z to give a short name to commonly used objects. Don't confuse the original load module import x = require('name') grammar, which creates an alias for the specified symbol.

You can use this method to create aliases for any identifier, including objects in the imported module:

// alias

namespace Shapes {
    export namespace Polygons {
        export class Triangle {  }
        export class Square { }
    }
}

import polygons = Shapes.Polygons;

let sq = new polygons.Square(); // Same as "new Shapes.Polygons.Square()"

After compilation:

// alias
var Shapes;
(function (Shapes) {
    var Polygons;
    (function (Polygons) {
        var Triangle = /** @class */ (function () {
            function Triangle() {
            }
            return Triangle;
        }());
        Polygons.Triangle = Triangle;
        var Square = /** @class */ (function () {
            function Square() {
            }
            return Square;
        }());
        Polygons.Square = Square;
    })(Polygons = Shapes.Polygons || (Shapes.Polygons = {}));
})(Shapes || (Shapes = {}));
var polygons = Shapes.Polygons;
var sq = new polygons.Square(); // Same as "new Shapes.Polygons.Square()"

Note that instead of using the require keyword, you import the qualified name assignment of the symbol directly. This is similar to var, but it also applies to types and imported symbols with namespace meanings. Importantly, for values, import generates references that are different from the original symbol, so changing the VaR value of the alias does not affect the value of the original variable.

5. Use other JavaScript Libraries

To describe the types of class libraries that are not written by TypeScript, you need to declare the API s exported by the class libraries. Since most libraries provide only a few top-level objects, namespaces are a good way to represent them.

We call it a declaration because it is not a concrete implementation of an external program. We usually write these statements in.d.ts. If you are familiar with C/C++, you can use it as an. h file.

External namespaces

The popular library D3 defines its functions in global object d3. Because the library is loaded through a script tag (not through a module loader), its declaration file uses internal modules to define its type. In order for the TypeScript compiler to recognize its type, we use an external namespace declaration. For example:

declare namespace D3 {
    export interface Selectors {
        select: {
            (selector: string): Selection;
            (element: EventTarget): Selection;
        };
    }

    export interface Event {
        x: number;
        y: number;
    }

    export interface Base extends Selectors {
        event: Event;
    }
}

declare var d3: D3.Base;

6. Sample Code

This article's sample code:

Copyright of articles: Postbird-There I am , in the world more exciting!

Links to this article: http://www.ptbird.cn/typescript-namespace.html

Reprinted please indicate the original source of the article!

Keywords: Javascript TypeScript github

Added by amosse on Tue, 06 Aug 2019 12:08:55 +0300