TypeScript

8     Classes

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.

8.1    Class Declarations

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   TypeParametersopt   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.5.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.

8.1.1     Class Heritage Specification

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:
ClassExtendsClauseopt   ImplementsClauseopt

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.3) of the declared class must be a subtype (section 3.8.2) of 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 a subtype of the base class constructor function type, ignoring construct signatures.

The following example illustrates a situation in which the second 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.

8.1.2     Class Body

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:
ClassElementsopt

ClassElements:
ClassElement
ClassElements   ClassElement

ClassElement:
ConstructorDeclaration
MemberDeclaration
IndexSignature

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. Member declarations are described in section 8.4.

8.2    Members

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.

8.2.1     Instance and Static Members

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.3) 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 excluding construct signatures.

Type parameters cannot be referenced in static member declarations.

8.2.2     Accessibility

Members have either public or private accessibility. The default is public accessibility, but member declarations may include a public or private modifier to explicitly specify the desired accessibility.

Public members can be accessed everywhere, but private members can be accessed only within the class body that contains their declaration. Any attempt to access a private 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.

8.2.3     Inheritance and Overriding

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 members are inherited, but only public members can be overridden. A member in a derived class is said to override a member in a base class when the derived class member has the same name and kind (instance or static) as the base class member. The type of an overriding member must be a subtype (section 3.8.2) of the type of the overridden 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 members can be overridden by derived class static members of any kind as long as the types are compatible, as described above.

8.2.4     Class Types

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.3) 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 or private modifier.

·         All base class instance type properties that are not overridden in the class.

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’.

8.2.5     Constructor Function Types

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’ of the class instance type.

·         All base class constructor function type properties that are not overridden in the class.

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.

8.3    Constructor Declarations

A constructor declaration declares the constructor function of a class.

ConstructorDeclaration:
ConstructorOverloadsopt   ConstructorImplementation

ConstructorOverloads:
ConstructorOverload
ConstructorOverloads   ConstructorOverload

ConstructorOverload:
constructor   (   ParameterListopt   )   ;

ConstructorImplementation:
constructor   (   ParameterListopt   )   {   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.

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.

8.3.1     Constructor Parameters

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
    }
}

8.3.2     Super Calls

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.

8.3.3     Automatic Constructors

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.

8.4    Member Declarations

Member declarations can be member variable declarations, member function declarations, or member accessor declarations.

MemberDeclaration:
MemberVariableDeclaration
MemberFunctionDeclaration
MemberAccessorDeclaration

Member declarations without a static modifier are called instance member declarations. Instance member declarations declare properties in the class instance type (section 8.2.4), and must specify names that are unique among all instance 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 member declarations declare properties in the constructor function type (section 8.2.5), and must specify names that are unique among all static 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 members are separate. Thus, it is possible to have instance and statics 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 member with the same name and kind (instance or static) as a base class member.

Every class automatically contains a static member named ‘prototype’, the type of which is the containing class with type Any substituted for each type parameter. It is an error to explicitly declare a static member with the name ‘prototype’.

Below is an example of a class containing both instance and static 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;
}

8.4.1     Member Variable Declarations

A member variable declaration declares an instance member variable or a static member variable.

MemberVariableDeclaration:
PublicOrPrivateopt   
staticopt   PropertyName   TypeAnnotationopt   Initialiseropt   ;

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.

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 = [];
    }
}

8.4.2     Member Function Declarations

A member function declaration declares an instance member function or a static member function.

MemberFunctionDeclaration:
MemberFunctionOverloadsopt   MemberFunctionImplementation

MemberFunctionOverloads:
MemberFunctionOverload
MemberFunctionOverloads   MemberFunctionOverload

MemberFunctionOverload:
PublicOrPrivateopt   
staticopt   PropertyName   CallSignature   ;

MemberFunctionImplementation:
PublicOrPrivateopt   staticopt   PropertyName   CallSignature   {   FunctionBody   }

A member function declaration is processed in the same manner as an ordinary function declaration (section 6.1), except that in a member function this has a known type.

All overloads of a member function much 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 static member function declaration, the type of this is the constructor function type excluding construct signatures. (Construct signatures are excluded because a derived class constructor function is not guaranteed to have the same set of construct signatures as a base class constructor function.)

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;
    }
}

8.4.3     Member Accessor Declarations

A member accessor declaration declares an instance member accessor or a static member accessor.

MemberAccessorDeclaration:
PublicOrPrivateopt   
staticopt   GetAccessor
PublicOrPrivateopt   
staticopt   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 excluding construct signatures.

Get and set accessors are emitted as calls to ‘Object.defineProperty’ in the generated JavaScript, as described in section 8.5.1.

8.5    Code Generation

This section describes the structure of the JavaScript code generated from TypeScript classes.

8.5.1     Classes Without Extends Clauses

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.

8.5.2     Classes With Extends Clauses

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.

 


TypeScript Language Specification (converted to HTML pages by @Bartvds)

Version 0.9.1

August 2013

Microsoft is making this Specification available under the Open Web Foundation Final Specification Agreement  Version 1.0 ('OWF 1.0') as of October 1, 2012. The OWF 1.0 is available at  http://www.openwebfoundation.org/legal/the-owf-1-0-agreements/owfa-1-0.

TypeScript is a trademark of Microsoft Corporation.