TypeScript Namespaces
The most explicit purpose of namespaces is to solve the problem of name collisions.
Suppose there is a situation where there are two students named Xiaoming in a class. To clearly distinguish between them, we have to use additional information beyond their names, such as their surnames (Wang Xiaoming, Li Xiaoming), or their parents' names, etc.
Namespaces define the scope of visibility for identifiers. An identifier can be defined in multiple namespaces, and its meaning in different namespaces is independent of each other. This way, any identifier can be defined in a new namespace without conflicting with any existing identifiers, as the existing definitions are in other namespaces.
In TypeScript, namespaces are defined using namespace
, with the following syntax:
namespace SomeNameSpaceName {
export interface ISomeInterfaceName { }
export class SomeClassName { }
}
The above defines a namespace SomeNameSpaceName. If we need to call the classes and interfaces from SomeNameSpaceName externally, we need to add the export
keyword to the classes and interfaces.
To call from another namespace, the syntax is:
SomeNameSpaceName.SomeClassName;
If a namespace is in a separate TypeScript file, it should be referenced using triple slashes ///, with the following syntax:
/// <reference path = "SomeFileName.ts" />
The following example demonstrates the use of namespaces defined in different files:
IShape.ts File Code:
namespace Drawing {
export interface IShape {
draw();
}
}
Circle.ts File Code:
/// <reference path = "IShape.ts" />
namespace Drawing {
export class Circle implements IShape {
public draw() {
console.log("Circle is drawn");
}
}
}
Triangle.ts File Code:
/// <reference path = "IShape.ts" />
namespace Drawing {
export class Triangle implements IShape {
public draw() {
console.log("Triangle is drawn");
}
}
}
TestShape.ts File Code:
/// <reference path = "IShape.ts" />
/// <reference path = "Circle.ts" />
/// <reference path = "Triangle.ts" />
function drawAllShapes(shape: Drawing.IShape) {
shape.draw();
}
drawAllShapes(new Drawing.Circle());
drawAllShapes(new Drawing.Triangle());
Compile the above code using the tsc command:
tsc --out app.js TestShape.ts
This produces the following JavaScript code:
JavaScript
/// <reference path = "IShape.ts" />
var Drawing;
(function (Drawing) {
var Circle = /** @class */ (function () {
function Circle() {
}
Circle.prototype.draw = function () {
console.log("Circle is drawn");
};
return Circle;
}());
Drawing.Circle = Circle;
})(Drawing || (Drawing = {}));
/// <reference path = "IShape.ts" />
var Drawing;
(function (Drawing) {
var Triangle = /** @class */ (function () {
function Triangle() {
}
Triangle.prototype.draw = function () {
console.log("Triangle is drawn");
};
return Triangle;
}());
Drawing.Triangle = Triangle;
})(Drawing || (Drawing = {}));
/// <reference path = "IShape.ts" />
/// <reference path = "Circle.ts" />
/// <reference path = "Triangle.ts" />
function drawAllShapes(shape) {
shape.draw();
}
drawAllShapes(new Drawing.Circle());
drawAllShapes(new Drawing.Triangle());
View the output using the node command:
$ node app.js
Circle is drawn
Triangle is drawn
Nested Namespaces
Namespaces support nesting, meaning you can define a namespace inside another namespace.
namespace namespace_name1 {
export namespace namespace_name2 {
export class class_name { }
}
}
Access members using the dot .
operator, as shown in the following example:
Invoice.ts File Code:
namespace tutorialpro {
export namespace invoiceApp {
export class Invoice {
public calculateDiscount(price: number) {
return price * .40;
}
}
}
}
InvoiceTest.ts File Code:
/// <reference path = "Invoice.ts" />
var invoice = new tutorialpro.invoiceApp.Invoice();
console.log(invoice.calculateDiscount(500));
Compile the above code using the tsc command:
tsc --out app.js InvoiceTest.ts
This produces the following JavaScript code:
JavaScript
var tutorialpro;
(function (tutorialpro) {
var invoiceApp;
(function (invoiceApp) {
var Invoice = /** @class */ (function () {
function Invoice() {
}
Invoice.prototype.calculateDiscount = function (price) {
return price * .40;
};
return Invoice;
}());
invoiceApp.Invoice = Invoice;
})(invoiceApp = tutorialpro.invoiceApp || (tutorialpro.invoiceApp = {}));
})(tutorialpro || (tutorialpro = {}));
/// <reference path = "Invoice.ts" />
var invoice = new tutorialpro.invoiceApp.Invoice();
console.log(invoice.calculateDiscount(500));
View the output using the node command:
$ node app.js
200