---
description: https://medium.com/jspoint/typescript-namespaces-f43cd002c08c
---

# \[TYPESCRIPT] Employing “Namespaces” in TypeScript to encapsulate your data

## Employing “Namespaces” in TypeScript to encapsulate your data <a href="#id-29fb" id="id-29fb"></a>

### In this lesson, we are going to learn about the precursor of the ECMAScript module implemented purely in TypeScript. These are called namespaces and they are quite fascinating. <a href="#id-30d0" id="id-30d0"></a>

[![Uday Hiwarale](https://miro.medium.com/fit/c/96/96/1*prggu1F7QvG7l6phOioNJg.gif)](https://medium.com/@thatisuday?source=post_page-----f43cd002c08c--------------------------------)[Uday Hiwarale](https://medium.com/@thatisuday?source=post_page-----f43cd002c08c--------------------------------)Follow[Aug 3](https://medium.com/jspoint/typescript-namespaces-f43cd002c08c?source=post_page-----f43cd002c08c--------------------------------) · 11 min read![Image for post](https://miro.medium.com/max/60/1*1007NPqZOG9glnzFnFK2Fg.png?q=20)![Image for post](https://miro.medium.com/max/1526/1*1007NPqZOG9glnzFnFK2Fg.png)(source: [**unsplash.com**](https://unsplash.com/photos/pdFMl6enmeo))

In the [**previous lesson**](https://medium.com/jspoint/typescript-module-system-5022cac310f6), we learn about the standard module system used by TypeScript which also coincides with the standard module system of JavaScript standardized by the ECMAScript.

When the `module` compiler-option (_or the `--module` flag_) is set to `CommonJS`, the TypeScript compiler converts the ECMAScript module statements such as `import` and `export` to equivalent `require` and `exports` statements for `Node`. Else, it is left intact so that it can work inside browsers that support native ECMAScript modules.

The benefit of using a module system in a project is that you can split reusable logic and application logic between multiple files. However, this also means your runtime environment must support one of these module systems.

If you want the compiled JavaScript program to run on `Node`, you can set the `module` compiler-option to `CommonJS`. If you want to run the program in a browser environment, you can use `ES2015` or `ES2020` value. However, you can’t really achieve isomorphic JavaScript that can run both on the `Node` and inside a browser at the moment using one of these module systems.

When a standard module system is not required or can’t be implemented but we still want to add some **modularity** to our project, **namespaces** are a way to go. Namespaces are a TypeScript feature that compiles to pure JavaScript without `require` or `import` statements in the output code.

Since they do not use a platform-dependent module system and they compile to vanilla JavaScript that we are used to since the stone age, they are called **internal modules**. Let’s dive into it.

### What are Namespaces? <a href="#id-6aa7" id="id-6aa7"></a>

You might be familiar with namespaces in programming languages like `C++` or `Java`. A namespace is like a region out of which things can not escape. The `namespace` keyword in TypeScript creates such a region.

```
// a.ts
var _version = '1.0.0';
function getVersion() {
    return _version;
}console.log( _version ); // 1.0.0
console.log( getVersion() ); // 1.0.0
```

In the above example, the `_version` variable is accessible by everyone which probably should have been only accessible in the `getVersion` function. Also, we do not want `getVersion` function to be in the global scope since a function with the same name could’ve been added by a third-party library in the global scope. We need to add some encapsulation over these values.

```
// a.ts
namespace MyLibA {
    const _version = '1.0.0';
    
    function getVersion() {
        return _version;
    }
}console.log( _version ); // ❌ ERROR
console.log( getVersion() ); // ❌ ERROR
```

In the above modification, we have wrapped the application logic code inside the namespace `MyLibA`. The `namespace { ... }` block is like a prison for the code inside. It can’t escape outside which means it can’t pollute the global scope. Therefore, nobody from the outside can access the values inside.

```
$ tsc a.ts
a.ts:9:14 - error TS2304: Cannot find name '_version'.
    console.log( _version ); // 1.0.0
                 ~~~~~~~~a.ts:10:14 - error TS2304: Cannot find name 'getVersion'
    console.log( getVersion() ); // 1.0.0
                 ~~~~~~~~~~
```

If we try to compile the program, the TypeScript compiler will not allow it since the `_version` and `getVersion` values are not defined in the global scope. To get access to them, we need to access them from the namespace.

```
namespace MyLibA {
    const _version = '1.0.0';export function getVersion() {
        return _version;
    }
}console.log( MyLibA._version ); // ❌ ERROR
console.log( MyLibA.getVersion() ); // 1.0.0
```

In the above example, we have added `export` keyword before the `getVersion` function to make it publically accessible from the namespace. However, the `_version` value is not exported, so it won’t be accessible on the namespace.

To access a value exported from the namespace, we use `<ns>.<value>` expression. The `MyLibA.getVersion` returns the `getVersion` function since it was exported from the `MyLibA` namespace but `MyLibA._version` won’t be accessible since it was not exported.

The syntax to export values from a namespace is as simple as putting `export` before a declaration whether it is a `let`, `var` or `const` variable declaration or `class`, `function` or even `enum` declaration as illustrated below.

```
namespace <name> {
  const private = 1;
  function privateFunc() { ... };export const public = 2;
  export function publicFunc() { ... };
}
```

So the time for the ultimate reveal. What do namespaces look like in the compiled javascript code? The answer should be obvious. Since we access public values of a namespace using `<ns>.<value>` expression, the `ns` most probably should be an object.

```
// a.js
var MyLibA;
(function (MyLibA) {
    var _version = '1.0.0';function getVersion() {
        return _version;
    }MyLibA.getVersion = getVersion;
})(MyLibA || (MyLibA = {}));console.log(MyLibA.getVersion()); // 1.0.0
```

When we compile the `a.ts` program, we get the above output. Every namespace in a TypeScript program produces an **empty variable** declaration (_with the same name as the namespace_) and an [**IIFE**](https://en.wikipedia.org/wiki/Immediately_invoked_function_expression) in the compile JavaScript.

The IIFE contains the code written inside a namespace, therefore the values do not pollute the global scope since they are scoped to the function. The `export` statements inside a namespace are converted to the property assignation statements as shown below.

```
MyLibA.getVersion = getVersion;
```

This makes `getVersion` value inside the IIFE available on the `MyLibA` global object and therefore anyone can access it. In contrast to that, the `_version` value isn’t accessible outside the IIFE.

### Exporting Types and Namespaces <a href="#aa99" id="aa99"></a>

Like a module, you can also export types from a namespace.

```
// a.ts
namespace MyLibA {
    export interface Person {
        name: string;
        age: number;
    }export function getPerson( name: string, age: number ): Person {
        return { name, age };
    }
}const ross: MyLibA.Person = MyLibA.getPerson( 'Ross', 30 );
```

In the above example, we are exporting the `Person` interface from the `MyLibA` namespace, therefore we can use `MyLibA.Person` in a type annotation expression. However, since `MyLibA.Person` is a type, it won’t exist in the compiled JavaScript code.

```
// a.js
var MyLibA;(function (MyLibA) {
    function getPerson(name, age) {
        return { name: name, age: age };
    }MyLibA.getPerson = getPerson;
})(MyLibA || (MyLibA = {}));var ross = MyLibA.getPerson('Ross', 30);
```

Since a namespace is also a value, you can also export a namespace from within a namespace. These are called **nested namespaces**.

```
// a.ts
namespace MyLibA {
    export namespace Types {
        export interface Person {
            name: string;
            age: number;
        }
    }export namespace Functions {
        export function getPerson( name: string, age: number ):
        Types.Person {
            return { name, age };
        }
    }
}const ross: MyLibA.Types.Person = MyLibA.Functions.getPerson( 'Ross Geller', 30 );
```

In the above example, the namespace `MyLibA` exports two namespaces viz. `Types` and `Functions`. Namespaces are **lexically scoped**, therefore the `getPerson` function can access `Types.Person` from the outer scope.

```
// a.js
var MyLibA;
(function (MyLibA) {var Functions;
    (function (Functions) {
        function getPerson(name, age) {
            return { name: name, age: age };
        }
        Functions.getPerson = getPerson;
    })(Functions = MyLibA.Functions || (MyLibA.Functions = {}));})(MyLibA || (MyLibA = {}));var ross = MyLibA.Functions.getPerson('Ross Geller', 30);
```

### Aliasing <a href="#c9b9" id="c9b9"></a>

In the previous example, we can see that the nested namespace can get messy and difficult to use pretty quickly. The `MyLibA.Functions.getPerson` syntax is quite a mouthful. To shorten this, we can reference it using a variable.

```
// a.ts
namespace MyLibA {
    export namespace Types {
        export interface Person {
            name: string;
            age: number;
        }
    }export namespace Functions {
        export function getPerson( name: string, age: number ):
        Types.Person {
            return { name, age };
        }
    }
}var Person = MyLibA.Types.Person; // ❌ ERROR
var API = MyLibA.Functions;const ross: Person = API.getPerson( 'Ross Geller', 30 );
```

In the above example, we have saved `MyLibA.Functions` into a constant `API` which is short, cute, and easy to use. However, the same doesn’t work for `Person` since `Person` is declared as a variable but `MyLibA.Types.Person` is a **type**. You could use `type Person = MyLibA.Types.Person` to make this work.

But TypeScript provides an easier syntax to create aliases for namespaces that works well with both exported **types** and **values**. Instead of `var <alias> =`, we need to use `import <alias> =` expression.

```
// a.ts
namespace MyLibA {
    export namespace Types {
        export interface Person {
            name: string;
            age: number;
        }
    }export namespace Functions {
        export function getPerson( name: string, age: number ):
        Types.Person {
            return { name, age };
        }
    }
}import Person = MyLibA.Types.Person;
import API = MyLibA.Functions;const ross: Person = API.getPerson( 'Ross Geller', 30 );
```

In the above example, we have just changed the `var <alias>` declarations to `import <alias>` expression. This shouldn’t be compared with ES6 `import` statement. This is just a syntactical sugar to create an alias for namespaces.

```
// a.js
var MyLibA;
(function (MyLibA) {var Functions;
    (function (Functions) {
        function getPerson(name, age) {
            return { name: name, age: age };
        }
        Functions.getPerson = getPerson;
    })(Functions = MyLibA.Functions || (MyLibA.Functions = {}));})(MyLibA || (MyLibA = {}));var API = MyLibA.Functions;
var ross = API.getPerson('Ross Geller', 30);
```

As you can see from the above output, aliasing a namespace export using `import` creates a variable that references the exported value. If an alias references a type, it is simply ignored in the compiled output.

### Importing Namespaces <a href="#d92e" id="d92e"></a>

To separate the application logic from reusable logic, we normally create different files and place them in separate directories. In the example above, we place namespace declarations in a separate file and import them using an `import` statement. Since namespaces are regular values, we can import them.

```
// a.ts
import { MyLibA } from './b';const ross: MyLibA.Person = MyLibA.getPerson( 'Ross Geller', 30 );--------------------------------------------------------------------// b.ts
export namespace MyLibA {
    export interface Person {
        name: string;
        age: number;
    }export function getPerson( name: string, age: number ): Person {
        return { name, age };
    }
}
```

The problem with this again is that we are becoming platform-dependent since the compiled JavaScript would need a module system at runtime as shown in the below output for the `CommonJS` module system.

```
// a.js
var b_1 = require( "./b" );
var ross = b_1.MyLibA.getPerson('Ross Geller', 30);--------------------------------------------------------------------// b.js
var MyLibA;
(function (MyLibA) {
    function getPerson(name, age) {
        return { name: name, age: age };
    }
    MyLibA.getPerson = getPerson;
})(MyLibA = exports.MyLibA || (exports.MyLibA = {}));
```

Since the `b.ts` file is already imported inside `a.ts`, you can simply use the `tsc`` `_`--module CommonJS`_` ``a.ts` command to compile this project and TypeScript compiler will automatically include `b.ts` in the compilation process.

### Modularization <a href="#fda8" id="fda8"></a>

TypeScript provides [**triple-slash directives**](https://www.typescriptlang.org/v2/docs/handbook/triple-slash-directives.html) which are nothing but JavaScript comments that help the TypeScript compiler to locate other TypeScript files and include them in the compilation process.

```
/// <reference path="./b.ts" />
```

You can compare these with the **preprocessor directives** used in `C` and `C++` language such as `#include "stdio.h"`. These must appear at the top of the file to attain special meaning. Since these directives are just comments, their job only exists at the compile-time.

The `path` attribute of this `reference` directive points to another TypeScript file to create a dependency. This is kinda similar to importing `b.ts` using `import` statement but without having to mention the import members.

When a reference of another TypeScript file is given using the `reference` directive, TypeScript automatically includes that files in the compilation process much like the `import` statement. All the global values of that file become available in the file where it was referenced.

```
// a.ts
/// <reference path="./b.ts"/>const ross: MyLibA.Person = MyLibA.getPerson( 'Ross Geller', 30 );--------------------------------------------------------------------// b.ts
namespace MyLibA {
    export interface Person {
        name: string;
        age: number;
    }export function getPerson( name: string, age: number ): Person {
        return { name, age };
    }
}
```

In the above example, we have referenced `b.ts` inside `a.ts` using `reference` directive. Using this, all the values inside `b.ts` that are in the global scope will be accessible inside `a.ts`. Also, we do not need to add `b.ts` in the compilation process, therefore the **`tsc a.ts`** command will do the job.

```
// a.js
var ross = MyLibA.getPerson('Ross Geller', 30);--------------------------------------------------------------------// b.js
var MyLibA;
(function (MyLibA) {
    function getPerson(name, age) {
        return { name: name, age: age };
    }
    MyLibA.getPerson = getPerson;
})(MyLibA || (MyLibA = {}));
```

We can’t run this project on `Node` since these are two separate files and we do not have `require()` statements in the compiled code that Node can use to load dependent files. We would first need to combine them as a single bundle and run using the command `$ node`` `_`bundle.js`_.

In the browser environment, we need to load `b.js` first and then `a.js` since `a.js` depends on `b.js` for `MyLibA` object initialization. So the `<script>` statement should look like this.

```
<script src="./b.js" />
<script src="./a.js" />
```

However, you can use `--outFile` flag with the `tsc` command to generate a bundle (_such as_ `tsc`` `_`--outFile bundle.js`_` ``a.ts`). The typeScript compiler will **automatically figure out the order of code precedence** in the compiled JavaScript based on the order of `reference` directives. Therefore `reference` directives are absolutely necessary for **internal modules**.

```
// bundle.js// (from b.ts)
var MyLibA;
(function (MyLibA) {
    function getPerson(name, age) {
        return { name: name, age: age };
    }MyLibA.getPerson = getPerson;
})(MyLibA || (MyLibA = {}));// (from a.ts)
var ross = MyLibA.getPerson('Ross Geller', 30);
```

### Extending Namespaces <a href="#aaaa" id="aaaa"></a>

In the [**interfaces**](https://medium.com/jspoint/typescript-interfaces-4a2af07c8070) lesson, we saw that when multiple interfaces with the same name are declared in the same module (_file_), TypeScript coerces them into one declaration by merging their properties together.

You can extend a predefined namespace by referencing the file which contains the original namespace (_using the `reference` directive_) and redeclaring the namespace with new values.

```
// a.ts
/// <reference path="./b.ts"/>const john: MyLibA.Person = MyLibA.defaultPerson;
const ross: MyLibA.Person = MyLibA.getPerson( 'Ross Geller', 30 );console.log( john ); // {name: 'John Doe', age: 21}
console.log( ross ); // {name: 'Ross Geller', age: 30}--------------------------------------------------------------------// b.ts
/// <reference path="./c.ts" />namespace MyLibA {
    export const defaultPerson: Person = getPerson( 'John Doe', 21 );
}--------------------------------------------------------------------// c.ts
namespace MyLibA {
    export interface Person {
        name: string;
        age: number;
    }export function getPerson( name: string, age: number ): Person {
        return { name, age };
    }
}
```

In the above example, since `b.ts` references `c.ts`, it has access to `MyLibA` namespace and it adds `defaultPerson` public value to this namespace. If you notice, the `MyLibA` namespace in the `b.ts` has access to all the public values (_exported only_) of the same namespace defined in `c.ts`.

The `a.ts` references `b.ts` and for it, the `MyLibA` namespace has `Person`, `getPerson` and `defaultPerson` members. When we bundle this project using the `tsc`` `_`--outFile bundle.js`_` ``a.ts` command, we get the following output.

```
// bundle.js// (from c.ts)
var MyLibA;
(function (MyLibA) {
    function getPerson(name, age) {
        return { name: name, age: age };
    }
    MyLibA.getPerson = getPerson;
})(MyLibA || (MyLibA = {}));// (from b.ts)
var MyLibA;
(function (MyLibA) {
    MyLibA.defaultPerson = MyLibA.getPerson('John Doe', 21);
})(MyLibA || (MyLibA = {}));// (from a.ts)
var john = MyLibA.defaultPerson;
var ross = MyLibA.getPerson('Ross Geller', 30);
```

Extending the namespace makes much more sense when we see the compiled JavaScript code. As you can see, the middle section belong to the `b.ts` file which adds `defaultPerson` property to the `MyLibA` object.

Now the million-dollar question, where we should use namespaces? My suggestion would be to **avoid it whenever you can**. We have a standard for modules in JavaScript now. Node.js would also one day fully support it but for now, you can set `--module` to `CommonJS`, it is that easy.

Namespaces **predate** JavaScript modules, therefore it’s not worth investing your money into something that will soon become obsolete. However, namespaces would be a good fit for **cross-browser JavaScript** applications where the ECMAScript module system is not available in older browsers but we have [**Webpack**](https://webpack.js.org/) and other bundling tools to make ECMAScript module cross-platform and backward compatible.

TypeScript doesn’t allow bundling of **ECMAScript** or **CommonJS** modules, which means you can’t have a single bundle file of a TypeScript project that uses these module systems. If having a single bundle file is mission-critical, then you can opt-in for namespaces. Again, [**Webpack**](https://webpack.js.org/) or other bundling tools can help you create a bundle without having to sacrifice anything.
