The remainder of this document is the formal specification of the TypeScript programming language and is intended to be read as an adjunct to the ECMAScript Language Specification (specifically, the ECMA- 262 Standard, 5th Edition). This document describes the syntactic grammar added by TypeScript along with the compile-time processing and type checking performed by the TypeScript compiler, but it only minimally discusses the run-time behavior of programs since that is covered by the ECMAScript specification.
The syntactic grammar added by TypeScript language is specified throughout this document using the existing conventions and production names of the ECMAScript grammar. In places where TypeScript augments an existing grammar production it is so noted. For example:
CallExpression: ( Modified )
...
super ( ArgumentList(opt) )
super . IdentifierName
The ( Modified )
annotation indicates that an existing grammar production is being replaced, and the ...
references the contents of the original grammar production.
Similar to the ECMAScript grammar, if the phrase "[no LineTerminator here]
" appears in the right-hand side of
a production of the syntactic grammar, it indicates that the production is not a match if a LineTerminator
occurs in the input stream at the indicated position.
TypeScript supports named types that can be organized in hierarchical namespaces. Namespaces are introduced by module declarations and named types are introduced by class, interface, and enum declarations. Named types are denoted by qualified names that extend from some root module (possibly the global module) to the point of their declaration. The example
module X {
export module Y {
export interface Z { }
}
export interface Y { }
}
declares two interface types with the qualified names X.Y.Z
and X.Y
relative to the root module in which
X
is declared.
In a qualified type name all identifiers but the last one refer to namespaces and the last identifier refers to a named type. Named type and namespace names are in separate declaration spaces and it is therefore possible for a named type and a namespace to have the same name, as in the example above.
The hierarchy formed by namespace and named type names partially mirrors that formed by module instances and members. The example
module A {
export module B {
export class C { }
}
}
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
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.
Declarations introduce names in the declaration spaces to which they belong. It is an error to have two names with same spelling in the same declaration space. Declaration spaces exist as follows:
- The global module and each external or internal module has a declaration space for variables (including functions, modules, class constructor functions, and enum objects), a declaration space for named types (classes, interfaces, and enums), and a declaration space for namespaces (containers of named types). Every declaration (whether local or exported) in a module contributes to one or more of these declaration spaces.
- Each external or internal module has a declaration space for exported members, a declaration space for exported named types, and a declaration space for exported namespaces. All export declarations in the module contribute to these declaration spaces. Each internal module's export declaration spaces are shared with other internal modules that have the same root module and the same qualified name starting from that root module.
- Each class declaration has a declaration space for instance members, a declaration space for static members, and a declaration space for type parameters.
- Each interface declaration has a declaration space for members and a declaration space for type parameters. An interface's declaration space is shared with other interfaces that have the same root module and the same qualified name starting from that root module.
- Each enum declaration has a declaration space for its enum members. An enum's declaration space is shared with other enums that have the same root module and the same qualified name starting from that root module.
- Each function declaration (including constructor, member function, and member accessor declarations) and each function expression has a declaration space for variables (parameters, local variables, and local functions) and a declaration space for type parameters.
- Each object literal has a declaration space for its properties.
- Each object type literal has a declaration space for its members.
Top-level declarations in a source file with no top-level import or export declarations belong to the global module. Top-level declarations in a source file with one or more top-level import or export declarations belong to the external module represented by that source file.
An internal module declaration contributes a namespace name (representing a container of types) and possibly a member name (representing the module instance) to the containing module. A class declaration contributes both a member name (representing the constructor function) and a type name (representing the class type) to the containing module. An interface declaration contributes a type name to the containing module. An enum declaration contributes both a member name (representing the enum object) and a type name (representing the enum type) to the containing module. Any other declaration contributes a member name to the declaration space to which it belongs.
The parent module of an entity is defined as follows:
- The parent module of an entity declared in an internal module is that internal module.
- The parent module of an entity declared in an external module is that external module.
- The parent module of an entity declared in the global module is the global module.
- The parent module of an external module is the global module.
The root module of an entity is defined as follows:
- The root module of a non-exported entity is the entity's parent module.
- The root module of an exported entity is the root module of the entity's parent module.
Intuitively, the root module of an entity is the outermost module body from within which the entity is reachable.
Interfaces, enums, and internal modules are "open ended," meaning that interface, enum, and internal module declarations with the same qualified name relative to a common root are automatically merged. For further details, see sections 7.2, 9.3, and 10.5.
Namespace, type, and member names exist in separate declaration spaces. Furthermore, declarations of
non-instantiated modules (modules that contain only interfaces or modules at all levels of nesting) do not
introduce a member name in their containing declaration space. This means that the following is
permitted, provided module X
contains only interface or module declarations at all levels of nesting:
module M {
module X { ... } // Namespace
interface X { ... } // Type
var X; // Member
}
If module X
above was an instantiated module (section 10.1) it would cause a member X
to be
introduced in M
. This member would conflict with the variable X
and thus cause an error.
Instance and static members in a class are likewise in separate declaration spaces. Thus the following is permitted:
class C {
x: number; // Instance member
static x: string; // Static member
}
The scope of a name is the region of program text within which it is possible to refer to the entity declared by that name without qualification of the name. The scope of a name depends on the context in which the name is declared. The contexts are listed below in order from outermost to innermost:
- The scope of an entity declared in the global module is the entire program text.
- The scope of an entity declared in an external module is the source file of that external module.
- The scope of an exported entity declared in an internal module is the body of that module and every internal module with the same root and the same qualified name relative to that root.
- The scope of a non-exported entity declared within an internal module declaration is the body of that internal module declaration.
- The scope of a type parameter declared in a class or interface declaration is that entire
declaration, including constraints,
extends
clause,implements
clause, and declaration body, but not including static member declarations. - The scope of a member declared in an enum declaration is the body of that declaration and every enum declaration with the same root and the same qualified name relative to that root.
- The scope of a type parameter declared in a call or construct signature is that entire signature declaration, including constraints, parameter list, and return type. If the signature is part of a function implementation, the scope includes the function body.
- The scope of a parameter, local variable, or local function declared within a function declaration (including a constructor, member function, or member accessor declaration) or function expression is the body of that function declaration or function expression.
Scopes may overlap, for example through nesting of modules and functions. When the scopes of two entities with the same name overlap, the entity with the innermost declaration takes precedence and access to the outer entity is either not possible or only possible by qualifying its name.
When an identifier is resolved as a TypeName (section 3.6.2), only classes, interfaces, enums, and type parameters are considered and other entities in scope are ignored.
When an identifier is resolved as a ModuleName (section 3.6.2), only modules are considered and other entities in scope are ignored.
When an identifier is resolved as a PrimaryExpression (section 4.3), only instantiated modules (section 10.1), classes, enums, functions, variables, and parameters are considered and other entities in scope are ignored.
Note that class and enum members are never directly in scope—they can only be accessed by applying
the dot (.
) operator to a class instance or enum object. This even includes members of the current
instance in a constructor or member function, which are accessed by applying the dot operator to this.
As the rules above imply, locally declared entities in an internal module are closer in scope than exported entities declared in other module declarations for the same internal module. For example:
var x = 1;
module M {
export var x = 2;
console.log(x); // 2
}
module M {
console.log(x); // 2
}
module M {
var x = 3;
console.log(x); // 3
}