TypeScript supports classes that are closely aligned with those proposed for ECMAScript 6, and includes extensions for instance and static member declarations and properties declared and initialized from constructor parameters.
NOTE: TypeScript currently doesn't support class expressions or nested class declarations from the ECMAScript 6 proposal.
Class declarations introduce named types and provide implementations of those types. Classes support inheritance, allowing derived classes to extend and specialize base classes.
ClassDeclaration:
class Identifier TypeParameters(opt) ClassHeritage { ClassBody }
A ClassDeclaration declares a class type and a constructor function, both with the name given by Identifier, in the containing module. The class type is created from the instance members declared in the class body and the instance members inherited from the base class. The constructor function is created from the constructor declaration, the static member declarations in the class body, and the static members inherited from the base class. The constructor function initializes and returns an instance of the class type.
The Identifier of a class declaration may not be one of the predefined type names (section 3.6.1).
A class may optionally have type parameters (section 3.4.1) that serve as placeholders for actual types to be provided when the class is referenced in type references. A class with type parameters is called a generic class. The type parameters of a generic class declaration are in scope in the entire declaration and may be referenced in the ClassHeritage and ClassBody.
The following example introduces both a named type called Point
(the class type) and a member called
Point
(the constructor function) in the containing module.
class Point {
constructor(public x: number, public y: number) { }
public length() { return Math.sqrt(this.x * this.x + this.y * this.y); }
static origin = new Point(0, 0);
}
The Point
type is exactly equivalent to
interface Point {
x: number;
y: number;
length(): number;
}
The Point
member is a constructor function whose type corresponds to the declaration
var Point: {
new(x: number, y: number): Point;
origin: Point;
};
The context in which a class is referenced distinguishes between the class instance type and the constructor function. For example, in the assignment statement
var p: Point = new Point(10, 20);
the identifier Point
in the type annotation refers to the class instance type, whereas the identifier Point
in the new
expression refers to the constructor function object.
The heritage specification of a class consists of optional extends
and implements
clauses. The extends
clause specifies the base class of the class and the implements
clause specifies a set of interfaces for
which to validate the class provides an implementation.
ClassHeritage:
ClassExtendsClause(opt) ImplementsClause(opt)
ClassExtendsClause:
extends ClassType
ClassType:
TypeReference
ImplementsClause:
implements ClassOrInterfaceTypeList
A class that includes an extends
clause is called a derived class, and the class specified in the extends
clause is called the base class of the derived class. When a class heritage specification omits the extends
clause, the class does not have a base class. However, as is the case with every object type, type
references (section 3.3.1) to the class will appear to have the members of the global interface type named
Object
unless those members are hidden by members with the same name in the class.
The following constraints must be satisfied by the class heritage specification or otherwise a compile-time error occurs:
- If present, the type reference specified in the
extends
clause must denote a class type. Furthermore, the TypeName part of the type reference is required to be a reference to the class constructor function when evaluated as an expression. - A class declaration may not, directly or indirectly, specify a base class that originates in the same declaration. In other words a class cannot, directly or indirectly, be a base class of itself, regardless of type arguments.
- The instance type (section 3.5.1) of the declared class must be assignable (section 3.8.4) to the
base type reference and each of the type references listed in the
implements
clause. - The constructor function type created by the class declaration must be assignable to the base class constructor function type, ignoring construct signatures.
The following example illustrates a situation in which the first rule above would be violated:
class A { a: number; }
module Foo {
var A = 1;
class B extends A { b: string; }
}
When evaluated as an expression, the type reference A
in the extends
clause doesn't reference the class
constructor function of A
(instead it references the local variable A
).
The only situation in which the last two constraints above are violated is when a class overrides one or more base class members with incompatible new members.
Note that because TypeScript has a structural type system, a class doesn't need to explicitly state that it
implements an interface—it suffices for the class to simply contain the appropriate set of instance
members. The implements
clause of a class provides a mechanism to assert and validate that the class
contains the appropriate sets of instance members, but otherwise it has no effect on the class type.
The class body consists of zero or more constructor or member declarations. Statements are not allowed in the body of a class—they must be placed in the constructor or in members.
ClassBody:
ClassElements(opt)
ClassElements:
ClassElement
ClassElements ClassElement
ClassElement:
ConstructorDeclaration
PropertyMemberDeclaration
IndexMemberDeclaration
The body of class may optionally contain a single constructor declaration. Constructor declarations are described in section 8.3.
Member declarations are used to declare instance and static members of the class. Property member declarations are described in section 8.4 and index member declarations are described in section 8.5.
The members of a class consist of the members introduced through member declarations in the class body and the members inherited from the base class.
Members are either instance members or static members.
Instance members are members of the class type (section 8.2.4) and its associated instance type. Within
constructors, instance member functions, and instance member accessors, the type of this
is the instance
type (section 3.5.1) of the class.
Static members are declared using the static
modifier and are members of the constructor function type
(section 8.2.5). Within static member functions and static member accessors, the type of this
is the
constructor function type.
Class type parameters cannot be referenced in static member declarations.
Property members have either public or private accessibility. The default is public accessibility, but
property member declarations may include a public
or private
modifier to explicitly specify the desired
accessibility.
Public property members can be accessed everywhere, but private property members can be accessed only within the class body that contains their declaration. Any attempt to access a private property member outside the class body that contains its declaration results in a compile-time error.
Private accessibility is enforced only at compile-time and serves as no more than an indication of intent.
Since JavaScript provides no mechanism to create private properties on an object, it is not possible to
enforce the private
modifier in dynamic code at run-time. For example, private accessibility can be
defeated by changing an object's static type to Any and accessing the member dynamically.
A derived class inherits all members from its base class it doesn't override. Inheritance means that a derived class implicitly contains all non-overridden members of the base class. Both public and private property members are inherited, but only public property members can be overridden.
A property member in a derived class is said to override a property member in a base class when the derived class property member has the same name and kind (instance or static) as the base class property member. The type of an overriding property member must be assignable (section 3.8.4) to the type of the overridden property member, or otherwise a compile-time error occurs.
Base class instance member functions can be overridden by derived class instance member functions, but not by other kinds of members.
Base class instance member variables and accessors can be overridden by derived class instance member variables and accessors, but not by other kinds of members.
Base class static property members can be overridden by derived class static property members of any kind as long as the types are compatible, as described above.
An index member in a derived class is said to override an index member in a base class when the derived class index member is of the same index kind (string or numeric) as the base class index member. The type of an overriding index member must be assignable (section 3.8.4) to the type of the overridden index member, or otherwise a compile-time error occurs.
A class declaration declares a new named type (section 3.5) called a class type. Within the constructor and
member functions of a class, the type of this
is the instance type (section 3.5.1) of this class type. The
class type has the following members:
- A property for each instance member variable declaration in the class body.
- A property of a function type for each instance member function declaration in the class body.
- A property for each uniquely named instance member accessor declaration in the class body.
- A property for each constructor parameter declared with a
public
orprivate
modifier. - An index signature for each instance index member declaration in the class body.
- All base class instance type property or index members that are not overridden in the class.
All instance property members (including those that are private) of a class must satisfy the constraints implied by the index members of the class as specified in section 3.7.4.
In the example
class A {
public x: number;
public f() { }
public g(a: any) { return undefined; }
static s: string;
}
class B extends A {
public y: number;
public g(b: boolean) { return false; }
}
the instance type of A
is
interface A {
x: number;
f: () => void;
g: (a: any) => any;
}
and the instance type of B
is
interface B {
x: number;
y: number;
f: () => void;
g: (b: boolean) => boolean;
}
Note that static declarations in a class do not contribute to the class type and its instance type—rather,
static declarations introduce properties on the constructor function object. Also note that the declaration
of g
in B
overrides the member inherited from A
.
The type of the constructor function introduced by a class declaration is called the constructor function type. The constructor function type has the following members:
- If the class contains no constructor declaration and has no base class, a single construct signature with no parameters, having the same type parameters as the class and returning the instance type of the class.
- If the class contains no constructor declaration and has a base class, a set of construct signatures with the same parameters as those of the base class constructor function type following substitution of type parameters with the type arguments specified in the base class type reference, all having the same type parameters as the class and returning the instance type of the class.
- If the class contains a constructor declaration with no overloads, a construct signature with the parameter list of the constructor implementation, having the same type parameters as the class and returning the instance type of the class.
- If the class contains a constructor declaration with overloads, a set of construct signatures with the parameter lists of the overloads, all having the same type parameters as the class and returning the instance type of the class.
- A property for each static member variable declaration in the class body.
- A property of a function type for each static member function declaration in the class body.
- A property for each uniquely named static member accessor declaration in the class body.
- A property named
prototype
, the type of which is an instantiation of the class type with type Any supplied as a type argument for each type parameter. - All base class constructor function type properties that are not overridden in the class.
Every class automatically contains a static property member named prototype
, the type of which is the
containing class with type Any substituted for each type parameter.
The example
class Pair<T1, T2> {
constructor(public item1: T1, public item2: T2) { }
}
class TwoArrays<T> extends Pair<T[], T[]> { }
introduces two named types corresponding to
interface Pair<T1, T2> {
item1: T1;
item2: T2;
}
interface TwoArrays<T> {
item1: T[];
item2: T[];
}
and two constructor functions corresponding to
var Pair: {
new <T1, T2>(item1: T1, item2: T2): Pair<T1, T2>;
}
var TwoArrays: {
new <T>(item1: T[], item2: T[]): TwoArrays<T>;
}
Note that the construct signatures in the constructor function types have the same type parameters as their class and return the instance type of their class. Also note that when a derived class doesn't declare a constructor, type arguments from the base class reference are substituted before construct signatures are propagated from the base constructor function type to the derived constructor function type.
A constructor declaration declares the constructor function of a class.
ConstructorDeclaration:
ConstructorOverloads(opt) ConstructorImplementation
ConstructorOverloads:
ConstructorOverload
ConstructorOverloads ConstructorOverload
ConstructorOverload:
PublicOrPrivate(opt) constructor ( ParameterList(opt) ) ;
ConstructorImplementation:
PublicOrPrivate(opt) constructor ( ParameterList(opt) ) { FunctionBody }
A class may contain at most one constructor declaration. If a class contains no constructor declaration, an automatic constructor is provided, as described in section 8.3.3.
Overloads and the implementation of a constructor may include a public
or private
accessibility modifier,
but only public constructors are supported and private constructors result in an error.
If a constructor declaration includes overloads, the overloads determine the construct signatures of the type given to the constructor function object, and the constructor implementation signature must be assignable to that type. Otherwise, the constructor implementation itself determines the construct signature. This exactly parallels the way overloads are processed in a function declaration (section 6.2).
The function body of a constructor is permitted to contain return statements. If return statements specify expressions, those expressions must be of types that are assignable to the instance type of the class.
The type parameters of a generic class are in scope and accessible in a constructor declaration.
Similar to functions, only the constructor implementation (and not constructor overloads) can specify
default value expressions for optional parameters. It is a compile-time error for such default value
expressions to reference this
. For each parameter with a default value, a statement that substitutes the
default value for an omitted argument is included in the JavaScript generated for the constructor function.
A parameter of a ConstructorImplementation may be prefixed with a public
or private
modifier. This is
called a parameter property declaration and is shorthand for declaring a property with the same name
as the parameter and initializing it with the value of the parameter. For example, the declaration
class Point {
constructor(public x: number, public y: number) {
// Constructor body
}
}
is equivalent to writing
class Point {
public x: number;
public y: number;
constructor(x: number, y: number) {
this.x = x;
this.y = y;
// Constructor body
}
}
Super calls (section 4.8.1) are used to call the constructor of the base class. A super call consists of the keyword super followed by an argument list enclosed in parentheses. For example:
class ColoredPoint extends Point {
constructor(x: number, y: number, public color: string) {
super(x, y);
}
}
Constructors of classes with no extends
clause may not contain super calls, whereas constructors of
derived classes must contain at least one super call somewhere in their function body. Super calls are not
permitted outside constructors or in local functions inside constructors.
The first statement in the body of a constructor must be a super call if both of the following are true:
- The containing class is a derived class.
- The constructor declares parameter properties or the containing class declares instance member variables with initializers.
In such a required super call, it is a compile-time error for argument expressions to reference this
.
Initialization of parameter properties and instance member variables with initializers takes place immediately at the beginning of the constructor body if the class has no base class, or immediately following the super call if the class is a derived class.
If a class omits a constructor declaration, an automatic constructor is provided.
In a class with no extends
clause, the automatic constructor has no parameters and performs no action
other than executing the instance member variable initializers (section 8.4.1), if any.
In a derived class, the automatic constructor has the same parameter list (and possibly overloads) as the base class constructor. The automatically provided constructor first forwards the call to the base class constructor using a call equivalent to
BaseClass.apply(this, arguments);
and then executes the instance member variable initializers, if any.
Property member declarations can be member variable declarations, member function declarations, or member accessor declarations.
PropertyMemberDeclaration:
MemberVariableDeclaration
MemberFunctionDeclaration
MemberAccessorDeclaration
Member declarations without a static
modifier are called instance member declarations. Instance
property member declarations declare properties in the class instance type (section 8.2.4), and must
specify names that are unique among all instance property member and parameter property declarations
in the containing class, with the exception that instance get and set accessor declarations may pairwise
specify the same name.
Member declarations with a static
modifier are called static member declarations. Static property
member declarations declare properties in the constructor function type (section 8.2.5), and must specify
names that are unique among all static property member declarations in the containing class, with the
exception that static get and set accessor declarations may pairwise specify the same name.
Note that the declaration spaces of instance and static property members are separate. Thus, it is possible to have instance and static property members with the same name.
Except for overrides, as described in section 8.2.3, it is an error for a derived class to declare a property member with the same name and kind (instance or static) as a base class member.
Every class automatically contains a static property member named prototype
, the type of which is an
instantiation of the class type with type Any supplied as a type argument for each type parameter. It is an
error to explicitly declare a static property member with the name prototype
.
Below is an example of a class containing both instance and static property member declarations:
class Point {
constructor(public x: number, public y: number) { }
public distance(p: Point) {
var dx = this.x - p.x;
var dy = this.y - p.y;
return Math.sqrt(dx * dx + dy * dy);
}
static origin = new Point(0, 0);
static distance(p1: Point, p2: Point) { return p1.distance(p2); }
}
The class instance type Point
has the members:
interface Point {
x: number;
y: number;
distance(p: Point);
}
and the constructor function Point
has a type corresponding to the declaration:
var Point: {
new(x: number, y: number): Point;
origin: Point;
distance(p1: Point, p2: Point): number;
}
A member variable declaration declares an instance member variable or a static member variable.
MemberVariableDeclaration:
PublicOrPrivate(opt) static(opt) PropertyName TypeAnnotation(opt) Initialiser(opt) ;
The type associated with a member variable declaration is determined in the same manner as an ordinary variable declaration (see section 5.1).
An instance member variable declaration introduces a member in the class instance type and optionally
initializes a property on instances of the class. Initializers in instance member variable declarations are
executed once for every new instance of the class and are equivalent to assignments to properties of this
in the constructor. In an initializer expression for an instance member variable, this
is of the class
instance type.
A static member variable declaration introduces a property in the constructor function type and optionally initializes a property on the constructor function object. Initializers in static member variable declarations are executed once when the containing program or module is loaded.
Initializer expressions for instance member variables are evaluated in the scope of the class constructor body but are not permitted to reference parameters or local variables of the constructor. This effectively means that entities from outer scopes by the same name as a constructor parameter or local variable are inaccessible in initializer expressions for instance member variables.
Since instance member variable initializers are equivalent to assignments to properties of this
in the
constructor, the example
class Employee {
public name: string;
public address: string;
public retired = false;
public manager: Employee = null;
public reports: Employee[] = [];
}
is equivalent to
class Employee {
public name: string;
public address: string;
public retired: boolean;
public manager: Employee;
public reports: Employee[];
constructor() {
this.retired = false;
this.manager = null;
this.reports = [];
}
}
A member function declaration declares an instance member function or a static member function.
MemberFunctionDeclaration:
MemberFunctionOverloads(opt) MemberFunctionImplementation
MemberFunctionOverloads:
MemberFunctionOverload
MemberFunctionOverloads MemberFunctionOverload
MemberFunctionOverload:
PublicOrPrivate(opt) static(opt) PropertyName CallSignature ;
MemberFunctionImplementation:
PublicOrPrivate(opt) static(opt) PropertyName CallSignature { FunctionBody }
A member function declaration is processed in the same manner as an ordinary function declaration
(section 6), except that in a member function this
has a known type.
All overloads of a member function must have the same accessibility (public or private) and kind (instance or static).
An instance member function declaration declares a property in the class instance type and assigns a
function object to a property on the prototype object of the class. In the body of an instance member
function declaration, this
is of the class instance type.
A static member function declaration declares a property in the constructor function type and assigns a
function object to a property on the constructor function object. In the body of a static member function
declaration, the type of this
is the constructor function type.
A member function can access overridden base class members using a super property access (section 4.8.2). For example
class Point {
constructor(public x: number, public y: number) { }
public toString() {
return "x=" + this.x + " y=" + this.y;
}
}
class ColoredPoint extends Point {
constructor(x: number, y: number, public color: string) {
super(x, y);
}
public toString() {
return super.toString() + " color=" + this.color;
}
}
In a static member function, this
represents the constructor function object on which the static member
function was invoked. Thus, a call to new this()
may actually invoke a derived class constructor:
class A {
a = 1;
static create() {
return new this();
}
}
class B extends A {
b = 2;
}
var x = A.create(); // new A()
var y = B.create(); // new B()
Note that TypeScript doesn't require or verify that derived constructor functions are subtypes of base
constructor functions. In other words, changing the declaration of B
to
class B extends A {
constructor(public b: number) {
super();
}
}
does not cause errors in the example, even though the call to the constructor from the create
function
doesn't specify an argument (thus giving the value undefined
to b
).
A member accessor declaration declares an instance member accessor or a static member accessor.
MemberAccessorDeclaration:
PublicOrPrivate(opt) static(opt) GetAccessor
PublicOrPrivate(opt) static(opt) SetAccessor
Get and set accessors are processed in the same manner as in an object literal (section 4.5), except that a contextual type is never available in a member accessor declaration.
Accessors for the same member name must specify the same accessibility.
An instance member accessor declaration declares a property in the class instance type and defines a
property on the prototype object of the class with a get or set accessor. In the body of an instance
member accessor declaration, this
is of the class instance type.
A static member accessor declaration declares a property in the constructor function type and defines a
property on the constructor function object of the class with a get or set accessor. In the body of a static
member accessor declaration, the type of this
is the constructor function type.
Get and set accessors are emitted as calls to Object.defineProperty
in the generated JavaScript, as
described in section 8.6.1.
An index member declaration introduces an index signature (section 3.7.4) in the class instance type.
IndexMemberDeclaration:
IndexSignature ;
Index member declarations have no body and cannot specify an accessibility modifier.
A class declaration can have at most one string index member declaration and one numeric index member declaration. All instance property members of a class must satisfy the constraints implied by the index members of the class as specified in section 3.7.4.
It is not possible to declare index members for the static side of a class.
Note that it is seldom meaningful to include a string index signature in a class because it constrains all instance properties of the class. However, numeric index signatures can be useful to control the element type when a class is used in an array-like manner.
This section describes the structure of the JavaScript code generated from TypeScript classes.
A class with no extends
clause generates JavaScript equivalent to the following:
var <ClassName> = (function () {
function <ClassName>(<ConstructorParameters>) {
<DefaultValueAssignments>
<ParameterPropertyAssignments>
<MemberVariableAssignments>
<ConstructorStatements>
}
<MemberFunctionStatements>
<StaticVariableAssignments>
return <ClassName>;
})();
ClassName is the name of the class.
ConstructorParameters is a comma separated list of the constructor's parameter names.
DefaultValueAssignments is a sequence of default property value assignments corresponding to those generated for a regular function declaration, as described in section 6.5.
ParameterPropertyAssignments is a sequence of assignments, one for each parameter property declaration in the constructor, in order they are declared, of the form
this.<ParameterName> = <ParameterName>;
where ParameterName is the name of a parameter property.
MemberVariableAssignments is a sequence of assignments, one for each instance member variable declaration with an initializer, in the order they are declared, of the form
this.<MemberName> = <InitializerExpression>;
where MemberName is the name of the member variable and InitializerExpression is the code generated for the initializer expression.
ConstructorStatements is the code generated for the statements specified in the constructor body.
MemberFunctionStatements is a sequence of statements, one for each member function declaration or member accessor declaration, in the order they are declared.
An instance member function declaration generates a statement of the form
<ClassName>.prototype.<MemberName> = function (<FunctionParameters>) {
<DefaultValueAssignments>
<FunctionStatements>
}
and static member function declaration generates a statement of the form
<ClassName>.<MemberName> = function (<FunctionParameters>) {
<DefaultValueAssignments>
<FunctionStatements>
}
where MemberName is the name of the member function, and FunctionParameters, DefaultValueAssignments, and FunctionStatements correspond to those generated for a regular function declaration, as described in section 6.5.
A get or set instance member accessor declaration, or a pair of get and set instance member accessor declarations with the same name, generates a statement of the form
Object.defineProperty(<ClassName>.prototype, "<MemberName>", {
get: function () {
<GetAccessorStatements>
},
set: function (<ParameterName>) {
<SetAccessorStatements>
},
enumerable: true,
configurable: true
};
and a get or set static member accessor declaration, or a pair of get and set static member accessor declarations with the same name, generates a statement of the form
Object.defineProperty(<ClassName>, "<MemberName>", {
get: function () {
<GetAccessorStatements>
},
set: function (<ParameterName>) {
<SetAccessorStatements>
},
enumerable: true,
configurable: true
};
where MemberName is the name of the member accessor, GetAccessorStatements is the code generated
for the statements in the get acessor's function body, ParameterName is the name of the set accessor
parameter, and SetAccessorStatements is the code generated for the statements in the set accessor's
function body. The get
property is included only if a get accessor is declared and the set
property is
included only if a set accessor is declared.
StaticVariableAssignments is a sequence of statements, one for each static member variable declaration with an initializer, in the order they are declared, of the form
<ClassName>.<MemberName> = <InitializerExpression>;
where MemberName is the name of the static variable, and InitializerExpression is the code generated for the initializer expression.
A class with an extends
clause generates JavaScript equivalent to the following:
var <ClassName> = (function (_super) {
__extends(<ClassName>, _super);
function <ClassName>(<ConstructorParameters>) {
<DefaultValueAssignments>
<SuperCallStatement>
<ParameterPropertyAssignments>
<MemberVariableAssignments>
<ConstructorStatements>
}
<MemberFunctionStatements>
<StaticVariableAssignments>
return <ClassName>;
})(<BaseClassName>);
In addition, the __extends
function below is emitted at the beginning of the JavaScript source file. It
copies all properties from the base constructor function object to the derived constructor function object
(in order to inherit static members), and appropriately establishes the prototype
property of the derived
constructor function object.
var __extends = this.__extends || function(d, b) {
for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p];
function f() { this.constructor = d; }
f.prototype = b.prototype;
d.prototype = new f();
}
BaseClassName is the class name specified in the extends
clause.
If the class has no explicitly declared constructor, the SuperCallStatement takes the form
_super.apply(this, arguments);
Otherwise the SuperCallStatement is present if the constructor function is required to start with a super call, as discussed in section 8.3.2, and takes the form
_super.call(this, <SuperCallArguments>)
where SuperCallArguments is the argument list specified in the super call. Note that this call precedes the code generated for parameter properties and member variables with initializers. Super calls elsewhere in the constructor generate similar code, but the code generated for such calls will be part of the ConstructorStatements section.
A super property access in the constructor, an instance member function, or an instance member accessor generates JavaScript equivalent to
_super.prototype.<PropertyName>
where PropertyName is the name of the referenced base class property. When the super property access appears in a function call, the generated JavaScript is equivalent to
_super.prototype.<PropertyName>.call(this, <Arguments>)
where Arguments is the code generated for the argument list specified in the function call.
A super property access in a static member function or a static member accessor generates JavaScript equivalent to
_super.<PropertyName>
where PropertyName is the name of the referenced base class property. When the super property access appears in a function call, the generated JavaScript is equivalent to
_super.<PropertyName>.call(this, <Arguments>)
where Arguments is the code generated for the argument list specified in the function call.