A Namespace Entity
is a named container for values and types providing a hierarchical
mechanism for organizing code and declarations.
Knowing how TypeScript transpiles namespaces into JavaScript code helps to understand the underlying mechanism of encapsulation, exports, and declaration merging. Continue reading this section.
name: Namespace declaration
NamespaceDeclaration:
`namespace` IdentifierPath `{` NamespaceBody `}`
IdentifierPath:
BindingIdentifier
IdentifierPath `.` BindingIdentifier
namespace X {
/* Empty */
}
name: Simple namespace declaration
entity:
type: namespace
extra: false
items:
- name: X
loc: 1:11
Using identifier path to declare a namespace is equivalent to declare multiple namespaces that hierarchically export its descendants.
namespace X.Y.Z {
/* Empty */
}
// Is equivalent to
// namespace X {
// export namespace Y {
// export namespace Z {
// /* Empty */
// }
// }
// }
name: Namespace identifier path
entity:
type: namespace
extra: false
items:
- name: X
qualified: X
loc: file0:1:11
- name: Y
qualified: X.Y
loc: file0:1:13
- name: Z
qualified: X.Y.Z
loc: file0:1:15
namespace A {
export type A = number
}
interface A {
A: string
}
type b = A['A'] // interface A - property A
type c = A.A // namespace A - type alias A
name: Access children of namespace
entity:
items:
- name: A
loc: 1:11
type: namespace
- name: A
qualified: A.A
loc: 2:17
type: type alias
- name: A
loc: 5:11
type: interface
- name: A
qualified: A.A
loc: 6:5
type: property
relation:
type: use
items:
- from: file:'file0'
to: property:'A.A'
loc: 9:10
- from: file:'file0'
to: type alias:'A.A'
loc: 10:10
namespace
is open-ended, which means namespaces with the same qualified name under
the same scope will be merged into a single one namespace.
Namespace can not only be merged with another namespace declaration, but also function, class, or enum declaration.
namespace X {
export const a = 1;
}
namespace X {
export const b = 2;
}
// Usage
// const x: typeof X = {a: 1, b: 2};
name: Single file namespace declaration merging
entity:
type: namespace
extra: false
items:
- name: X
loc: 1:11
type: namespace
declarations:
- 5:11
- name: a
qualified: X.a
loc: 2:18
type: variable
kind: const
- name: b
qualified: X.b
loc: 6:18
type: variable
kind: const
namespace X {
export const a = 1;
}
namespace X {
export const b = 2;
}
name: Multiple files namespace declaration merging
entity:
type: namespace
extra: false
items:
- name: X
loc: 1:11
type: namespace
declarations:
- file1:1:11
- name: a
qualified: X.a
loc: 2:18
type: variable
kind: const
- name: b
qualified: X.b
loc: 2:18
type: variable
kind: const
Variable declarations with var
can declare the same identifier multiple times
inter-/intra-namespace, whereas let
and const
do not satisfy this.
namespace X {
export var a = 1;
// export let b = 1;
// export const c = 1;
}
X.a // 1
namespace X {
export var a = 2;
// export let b = 2;
// export const c = 2;
}
X.a // 2
name: Redeclare block-scope variable
entity:
type: variable
extra: false
items:
- name: a
qualified: X.a
loc: 2:16
kind: var
relation:
type: set
extra: false
items:
- from: namespace:'X'
to: variable:'a'
loc: 2:16
init: true
- from: namespace:'X'
to: variable:'a'
loc: 10:16
init: true
When merging a non-ambient function or class declaration and a non-ambient namespace declaration, the function or class declaration must be located prior to the namespace declaration in the same source file. This ensures that the shared object instance is created as a function object. (While it is possible to add properties to an object after its creation, it is not possible to make an object "callable" after the fact.)
interface Point {
x: number;
y: number;
}
function point(x: number, y: number): Point {
return {x: x, y: y};
}
namespace point {
export var origin = point(0, 0);
export function equals(p1: Point, p2: Point) {
return p1.x == p2.x && p1.y == p2.y;
}
}
var p1 = point(0, 0);
var p2 = point.origin;
var b = point.equals(p1, p2);
name: Merge namespace and function
entity:
items:
- name: point
loc: 6:10
type: function
- name: point
loc: 10:11
type: namespace
- name: origin
qualified: point.origin
loc: 11:16
type: variable
kind: var
- name: equals
qualified: point.equals
loc: 13:21
type: function
relation:
items:
- from: file:'file0'
to: function:'point'
loc: 18:10
type: call
- from: file:'file0'
to: variable:'point.origin'
loc: 19:16
type: use
- from: file:'file0'
to: function:'point.equals'
loc: 20:15
type: call
NamespaceBody:
[NamespaceElements]
NamespaceElements:
NamespaceElement
NamespaceElements NamespaceElement
NamespaceElement:
Statement
LexicalDeclaration
FunctionDeclaration
GeneratorDeclaration
ClassDeclaration
InterfaceDeclaration
TypeAliasDeclaration
EnumDeclaration
NamespaceDeclaration
AmbientDeclaration
ImportAliasDeclaration
ExportNamespaceElement
ExportNamespaceElement:
`export` VariableStatement
`export` LexicalDeclaration
`export` FunctionDeclaration
`export` GeneratorDeclaration
`export` ClassDeclaration
`export` InterfaceDeclaration
`export` TypeAliasDeclaration
`export` EnumDeclaration
`export` NamespaceDeclaration
`export` AmbientDeclaration
`export` ImportAliasDeclaration
Name | Description | Type | Default |
---|---|---|---|
declarations | Each item is a code location where a merge-able declaration appears. | ENRELocation[] |
undefined |