10.1 Namespace Declarations

A namespace declaration introduces a name with a namespace meaning and, in the case of an instantiated namespace, a value meaning in the containing declaration space.

  NamespaceDeclaration:   namespaceIdentifierPath{NamespaceBody}

  IdentifierPath:   BindingIdentifier   IdentifierPath.BindingIdentifier

Namespaces are declared using the namespace keyword, but for backward compatibility of earlier versions of TypeScript a module keyword can also be used.

Namespaces are either instantiated or non-instantiated. A non-instantiated namespace is a namespace containing only interface types, type aliases, and other non-instantiated namespace. An instantiated namespace is a namespace that doesn’t meet this definition. In intuitive terms, an instantiated namespace is one for which a namespace instance is created, whereas a non-instantiated namespace is one for which no code is generated.

When a namespace identifier is referenced as a NamespaceName (section 3.8.2) it denotes a container of namespace and type names, and when a namespace identifier is referenced as a PrimaryExpression (section 4.3) it denotes the singleton namespace instance. For example:

  1. namespace M {
  2. export interface P { x: number; y: number; }
  3. export var a = 1;
  4. }
  5. var p: M.P; // M used as NamespaceName
  6. var m = M; // M used as PrimaryExpression
  7. var x1 = M.a; // M used as PrimaryExpression
  8. var x2 = m.a; // Same as M.a
  9. var q: m.P; // Error

Above, when ‘M’ is used as a PrimaryExpression it denotes an object instance with a single member ‘a’ and when ‘M’ is used as a NamespaceName it denotes a container with a single type member ‘P’. The final line in the example is an error because ‘m’ is a variable which cannot be referenced in a type name.

If the declaration of ‘M’ above had excluded the exported variable ‘a’, ‘M’ would be a non-instantiated namespace and it would be an error to reference ‘M’ as a PrimaryExpression.

A namespace declaration that specifies an IdentifierPath with more than one identifier is equivalent to a series of nested single-identifier namespace declarations where all but the outermost are automatically exported. For example:

  1. namespace A.B.C {
  2. export var x = 1;
  3. }

corresponds to

  1. namespace A {
  2. export namespace B {
  3. export namespace C {
  4. export var x = 1;
  5. }
  6. }
  7. }

The hierarchy formed by namespace and named type names partially mirrors that formed by namespace instances and members. The example

  1. namespace A {
  2. export namespace B {
  3. export class C { }
  4. }
  5. }

introduces a named type with the qualified name ‘A.B.C’ and also introduces a constructor function that can be accessed using the expression ‘A.B.C’. Thus, in the example

  1. var c: A.B.C = new A.B.C();

the two occurrences of ‘A.B.C’ in fact refer to different entities. It is the context of the occurrences that determines whether ‘A.B.C’ is processed as a type name or an expression.