TypeScript

7     Interfaces

Interfaces provide the ability to name and parameterize object types and to compose existing named object types into new ones.

Interfaces have no run-time representation—they are purely a compile-time construct. Interfaces are particularly useful for documenting and validating the required shape of properties, objects passed as parameters, and objects returned from functions.

Because TypeScript has a structural type system, an interface type with a particular set of members is considered identical to, and can be substituted for, another interface type or object type literal with an identical set of members (see section 3.8.1).

Class declarations may reference interfaces in their implements clause to validate that they provide an implementation of the interfaces.

7.1    Interface Declarations

An interface declaration declares a new named type (section 3.5) by introducing a type name in the containing module.

InterfaceDeclaration:
interface   Identifier   TypeParametersopt   InterfaceExtendsClauseopt   ObjectType

InterfaceExtendsClause:
extends   ClassOrInterfaceTypeList

ClassOrInterfaceTypeList:
ClassOrInterfaceType
ClassOrInterfaceTypeList   
,   ClassOrInterfaceType

ClassOrInterfaceType:
TypeReference

The Identifier of an interface declaration may not be one of the predefined type names (section 3.6.1).

An interface may optionally have type parameters (section 3.5.1) that serve as placeholders for actual types to be provided when the interface is referenced in type references. An interface with type parameters is called a generic interface. The type parameters of a generic interface declaration are in scope in the entire declaration and may be referenced in the InterfaceExtendsClause and ObjectType body.

An interface can inherit from zero or more base types which are specified in the InterfaceExtendsClause. The base types must be type references to class or interface types.

An interface has the members specified in the ObjectType of its declaration and furthermore inherits all base type members that aren’t hidden by declarations in the interface:

·         A property declaration hides a public base type property with the same name.

·         A call signature declaration hides a base type call signature that is identical when return types are ignored.

·         A construct signature declaration hides a base type construct signature that is identical when return types are ignored.

·         A string index signature declaration hides a base type string index signature.

·         A numeric index signature declaration hides a base type numeric index signature.

The following constraints must be satisfied by an interface declaration or otherwise a compile-time error occurs:

·         An interface declaration may not, directly or indirectly, specify a base type that originates in the same declaration. In other words an interface cannot, directly or indirectly, be a base type of itself, regardless of type arguments.

·         An interface cannot declare a property with the same name as an inherited private property.

·         Inherited properties with the same name must be identical (section 3.8.1).

·         The instance type (section 3.5.3) of the declared interface must be a subtype (section 3.8.2) of each of the base type references.

An interface is permitted to inherit identical members from multiple base types and will in that case only contain one occurrence of each particular member.

Below is an example of two interfaces that contain properties with the same name but different types:

interface Mover {
    move(): void;
    getStatus(): { speed: number; };
}

interface Shaker {
    shake(): void;
    getStatus(): { frequency: number; };
}

An interface that extends ‘Mover’ and ‘Shaker’ must declare a new ‘getStatus’ property as it would otherwise inherit two ‘getStatus’ properties with different types. The new ‘getStatus’ property must be declared such that the resulting ‘MoverShaker’ is a subtype of both ‘Mover’ and ‘Shaker’:

interface MoverShaker extends Mover, Shaker {
    getStatus(): { speed: number; frequency: number; };
}

Since function and constructor types are just object types containing call and construct signatures, interfaces can be used to declare named function and constructor types. For example:

interface StringComparer { (a: string, b: string): number; }

This declares type ‘StringComparer’ to be a function type taking two strings and returning a number.

7.2    Declaration Merging

Interfaces are “open-ended” and interface declarations with the same qualified name relative to a common root (as defined in section 2.3) contribute to a single interface.

When a generic interface has multiple declarations, all declarations must have identical type parameter lists, i.e. identical type parameter names with identical constraints in identical order.

In an interface with multiple declarations, the extends clauses are merged into a single set of base types and the bodies of the interface declarations are merged into a single object type.

7.3    Interfaces Extending Classes

When an interface type extends a class type it inherits the members of the class but not their implementations. It is as if the interface had declared all of the members of the class without providing an implementation. Interfaces inherit even the private members of a base class. When a class containing private members is the base type of an interface type, that interface type can only be implemented by that class or a descendant class. For example:

class Control {
    private state: any;
}

interface SelectableControl extends Control {
    select(): void;
}

class Button extends Control {
    select() { }
}

class TextBox extends Control {
    select() { }
}

class Image extends Control {
}

class Location {
    select() { }
}

In the above example, ‘SelectableControl’ contains all of the members of ‘Control’, including the private ‘state’ property. Since ‘state’ is a private member it is only possible for descendants of ‘Control’ to implement ‘SelectableControl’. This is because only descendants of ‘Control’ will have a ‘state’ private member that originates in the same declaration, which is a requirement for private members to be compatible (section 3.8).

Within the ‘Control’ class it is possible to access the ‘state’ private member through an instance of ‘SelectableControl’. Effectively, a ‘SelectableControl’ acts like a ‘Control’ that is known to have a ‘select’ method. The ‘Button’ and ‘TextBox’ classes are subtypes of ‘SelectableControl’ (because they both inherit from ‘Control’ and have a ‘select’ method), but the ‘Image’ and ‘Location’ classes are not.

7.4    Dynamic Type Checks

TypeScript does not provide a direct mechanism for dynamically testing whether an object implements a particular interface. Instead, TypeScript code can use the JavaScript technique of checking whether an appropriate set of members are present on the object. For example, given the declarations in section 7.1, the following is a dynamic check for the ‘MoverShaker’ interface:

var obj: any = getSomeObject();
if (obj && obj.move && obj.shake && obj.getStatus) {
    var moverShaker = <MoverShaker> obj;
    ...
}

If such a check is used often it can be abstracted into a function:

function asMoverShaker(obj: any): MoverShaker {
    return obj && obj.move && obj.shake && obj.getStatus ? obj : null;
}

 


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.