TypeScript

4     Expressions

This chapter describes the manner in which TypeScript provides type inference and type checking for JavaScript expressions. TypeScript’s type analysis occurs entirely at compile-time and adds no run-time overhead to expression evaluation.

TypeScript’s typing rules define a type for every expression construct. For example, the type of the literal 123 is the Number primitive type, and the type of the object literal { a: 10, b: "hello" } is { a: number; b: string; }. The sections in this chapter describe these rules in detail.

In addition to type inference and type checking, TypeScript adds the following expression constructs:

·         Optional parameter and return type annotations in function expressions.

·         Default parameter values and rest parameters in function expressions.

·         Arrow function expressions.

·         Super calls and member access.

·         Type assertions.

Unless otherwise noted in the sections that follow, TypeScript expressions and the JavaScript expressions generated from them are identical.

4.1    Values and References

Expressions are classified as values or references. References are the subset of expressions that are permitted as the target of an assignment. Specifically, references are combinations of identifiers (section 4.3), parentheses (section 4.7), and property accesses (section 4.10). All other expression constructs described in this chapter are classified as values.

4.2    The this Keyword

The type of this in an expression depends on the location in which the reference takes place:

·         In a constructor, member function, member accessor, or member variable initializer, this is of the class instance type of the containing class.

·         In a static function or static accessor, this is of a type corresponding to the constructor function type of the containing class without any construct signatures.

·         In a function declaration or a standard function expression, this is of type Any.

·         In the global module, this is of type Any.

In all other contexts it is a compile-time error to reference this.

In the body of an arrow function expression, references to this are rewritten in the generated JavaScript code, as described in section 4.9.2.

4.3    Identifiers

When an expression is an Identifier, the expression refers to the most nested module, class, enum, function, variable, or parameter with that name whose scope (section 2.4) includes the location of the reference.

The type of the expression is the type associated with the referenced entity:

·         For a module, the object type associated with the module instance.

·         For a class, the constructor type associated with the constructor function object.

·         For an enum, the object type associated with the enum object.

·         For a function, the function type associated with the function object.

·         For a variable, the type of the variable.

·         For a parameter, the type of the parameter.

In all cases the expression is classified as a reference.

4.4    Literals

Literals are typed as follows:

·         The type of the null literal is the Null primitive type.

·         The type of the literals true and false is the Boolean primitive type.

·         The type of numeric literals is the Number primitive type.

·         The type of string literals is the String primitive type.

·         The type of regular expression literals is the global interface type ‘RegExp’.

4.5    Object Literals

Object literals are extended to support type annotations in get and set accessors.

PropertyAssignment:  ( Modified )
PropertyName   
:   AssignmentExpression
PropertyName   CallSignature   
{   FunctionBody   }
GetAccessor

SetAccessor

GetAccessor:
get   PropertyName   (   )   TypeAnnotationopt   {   FunctionBody   }

SetAccessor:
set   PropertyName   (   Identifier   TypeAnnotationopt   )   {   FunctionBody   }

The type of an object literal is an object type with the set of properties specified by the property assignments in the object literal. A get and set accessor may specify the same property name, but otherwise it is an error to specify multiple property assignments for the same property.

A property assignment of the form

PropertyName CallSignature { FunctionBody }

is simply shorthand for

PropertyName : function CallSignature { FunctionBody }

Each property assignment in an object literal is processed as follows:

·         If the object literal is contextually typed and the contextual type contains a property with a matching name, the property assignment is contextually typed by the type of that property.

·         Otherwise, if the object literal is contextually typed, the contextual type contains a numeric index signature, and the property assignment specifies a numeric property name, the property assignment is contextually typed by the type of the numeric index signature.

·         Otherwise, if the object literal is contextually typed and the contextual type contains a string index signature, the property assignment is contextually typed by the type of the string index signature.

·         Otherwise, the property assignment is processed without a contextual type.

The type of a property introduced by a property assignment of the form Name : Expr is the widened form (section 3.9) of the type of Expr.

A get accessor declaration is processed in the same manner as an ordinary function declaration (section 6.1) with no parameters. A set accessor declaration is processed in the same manner as an ordinary function declaration with a single parameter and a Void return type. When both a get and set accessor is declared for a property:

·         If both accessors include type annotations, the specified types must be identical.

·         If only one accessor includes a type annotation, the other behaves as if it had the same type annotation.

·         If neither accessor includes a type annotation, the inferred return type of the get accessor becomes the parameter type of the set accessor.

If a get accessor is declared for a property, the return type of the get accessor becomes the type of the property. If only a set accessor is declared for a property, the parameter type (which may be type Any if no type annotation is present) of the set accessor becomes the type of the property.

When an object literal is contextually typed by a type that includes a string index signature of type T, the resulting type of the object literal includes a string index signature with the best common type of T and the types of the properties declared in the object literal. Likewise, when an object literal is contextually typed by a type that includes a numeric index signature of type T, the resulting type of the object literal includes a numeric index signature with the best common type of T and the types of the numerically named properties (section 3.7.4) declared in the object literal.

4.6    Array Literals

In the absence of a contextual type, the type of an array literal is C[], where C is the best common type of the element expressions. Note that the type of an empty array literal is any[] since the Any type is the best common type of an empty set of types.

When an array literal is contextually typed (section 4.18) by an object type containing a numeric index signature of type T, each element expression is contextually typed by T and the type of the array literal is the best common type of T and the types of the element expressions.

4.7    Parentheses

A parenthesized expression

( Expression )

has the same type and classification as the Expression itself. Specifically, if the contained expression is classified as a reference, so is the parenthesized expression.

4.8    The super Keyword

The super keyword can be used in expressions to reference base class properties and the base class constructor.

CallExpression:  ( Modified )

super   (   ArgumentListopt   )
super   .   IdentifierName

4.8.1     Super Calls

Super calls consist of the keyword super followed by an argument list enclosed in parentheses. Super calls are only permitted in constructors of derived classes, as described in section 8.3.2.

A super call invokes the constructor of the base class on the instance referenced by this. A super call is processed as a function call (section 4.12) using the construct signatures of the base class constructor function type as the initial set of candidate signatures for overload resolution. Type arguments cannot be explicitly specified in a super call. If the base class is a generic class, the type arguments used to process a super call are always those specified in the extends clause that references the base class.

The type of a super call expression is Void.

The JavaScript code generated for a super call is specified in section 8.5.2.

4.8.2     Super Property Access

A super property access consists of the keyword super followed by a dot and an identifier. Super property accesses are used to access base class member functions from derived classes.

Super property accesses are permitted as follows:

·         In a constructor, instance member function, or instance member accessor of a derived class, a super property access must specify a public instance member function of the base class.

·         In a static member function or static member accessor of a derived class, a super property access must specify a public static member function of the base class.

Super property accesses are not permitted in other contexts, and it is not possible to access other kinds of base class members in a super property access.

Super property accesses are typically used to access overridden base class member functions from derived class member functions. For an example of this, see section 8.4.2.

The JavaScript code generated for a super property access is specified in section 8.5.2.

4.9    Function Expressions

Function expressions are extended from JavaScript to optionally include parameter and return type annotations, and a new compact form, called arrow function expressions, is introduced.

FunctionExpression:  ( Modified )
function   Identifieropt   CallSignature   {   FunctionBody   }

AssignmentExpression:  ( Modified )

ArrowFunctionExpression

ArrowFunctionExpression:
ArrowFormalParameters   
=>   Block
ArrowFormalParameters   
=>   AssignmentExpression

ArrowFormalParameters:
CallSignature
Identifier

The terms standard function expression and arrow function expression are used to refer to the FunctionExpression and ArrowFunctionExpression forms respectively. When referring to either, the generic term function expression is used.

The type of a function expression is an object type containing a single call signature with parameter and return types inferred from the function expression’s signature and body.

The descriptions of function declarations provided in section 6.1 apply to function expressions as well, except that function expressions do not support overloading.

4.9.1     Standard Function Expressions

Standard function expressions are function expressions written with the function keyword. The type of this in a standard function expression is the Any type.

Standard function expressions are transformed to JavaScript in the same manner as function declarations (see section 6.5).

4.9.2     Arrow Function Expressions

TypeScript supports arrow function expressions, a new feature planned for ECMAScript 6. Arrow function expressions are a compact form of function expressions that omit the function keyword and have lexical scoping of this.

An arrow function expression of the form

ArrowFormalParameters => AssignmentExpression

is exactly equivalent to

ArrowFormalParameters => { return AssignmentExpression ; }

Furthermore, arrow function expressions of the forms

Identifier => Block
Identifier => AssignmentExpression

are exactly equivalent to

( Identifier ) => Block
(
Identifier ) => AssignmentExpression

Thus, the following examples are all equivalent:

(x) => { return Math.sin(x); }
(x) => Math.sin(x)
x => { return Math.sin(x); }
x => Math.sin(x)

A function expression using the function keyword introduces a new dynamically bound this, whereas an arrow function expression preserves the this of its enclosing context. Arrow function expressions are particularly useful for writing callbacks, which otherwise often have an undefined or unexpected this.

In the example

class Messenger {
    message = "Hello World";
    start() {
        setTimeout(() => alert(this.message), 3000);
    }
};
var messenger = new Messenger();
messenger.start();

the use of an arrow function expression causes the callback to have the same this as the surrounding ‘start’ method. Writing the callback as a standard function expression it becomes necessary to manually arrange access to the surrounding this, for example by copying it into a local variable:

class Messenger {
    message = "Hello World";
    start() {
        var _this = this;
        setTimeout(function() { alert(_this.message); }, 3000);
    }
};
var messenger = new Messenger();
messenger.start();

The TypeScript compiler applies this type of transformation to rewrite arrow function expressions into standard function expressions.

A construct of the form

< Identifier > ( ParamList ) => { ... }

could be parsed as an arrow function expression with a type parameter or a type assertion applied to an arrow function with no type parameter. It is resolved as the former, but parentheses can be used to select the latter meaning:

< Identifier > ( ( ParamList ) => { ... } )

4.9.3     Contextually Typed Function Expressions

Function expressions with no type parameters and no parameter or return type annotations (but possibly with optional parameters and default parameter values) are contextually typed in certain circumstances, as described in section 4.18. When a function expression is contextually typed by a function type T, the function expression is processed as if it had explicitly specified parameter type annotations as they exist in T. Parameters are matched by position and need not have matching names. If the function expression has fewer parameters than T, the additional parameters in T are ignored. If the function expression has more parameters than T, the additional parameters are all considered to have type Any.

When a function expression is contextually typed by a generic function type, parameters may be given types that are not directly denotable. In the example

interface Comparable<T> {
    compareTo(other: T): number;
}

interface Comparer {
    <T extends Comparable<T>>(x: T, y: T): number;
}

var f: Comparer = (x, y) => {
    var z: any;  // No name for type of x and y
    ...
}

the ‘Comparer’ type represents a function that can compare two values of some type ‘T’, where ‘T’ must implement ‘Comparable<T>’. In the function expression assigned to ‘f’, contextual typing provides a type for ‘x’ and ‘y’ that is identical in structure to the type parameter in ‘Comparer’ (i.e. ‘x’ and ‘y’ will have a ‘compareTo’ method taking an argument of the same type as themselves), but no name is introduced for the type. In order to introduce a name for the type the function expression must be explicitly typed:

var f: Comparer = <T extends Comparable<T>>(x: T, y: T) => {
    var z: T;  // Z has same type as x and y
    ...
}

4.10 Property Access

A property access uses either dot notation or bracket notation. A property access expression is always classified as a reference.

A property access applied to a value of the primitive type Number, Boolean, or String behaves exactly as a property access applied to an object of the global interface type ‘Number’, ‘Boolean’, or ‘String’ respectively. Likewise, a property access applied to a value of an enum type behaves exactly as a property access applied to an object of the global interface type ‘Number’.

In a property access, an object (including Number, Boolean, or String) appears to have additional properties that originate in the ‘Object’ or ‘Function’ global interface types, as described in section 3.3, and a type parameter appears to have the properties of its declared constraint, as described in section 3.4.

A dot notation property access of the form

ObjExpr . Name

where ObjExpr is an expression and Name is an identifier (including, possibly, a reserved word), is used to access the property with the given name on the given object. A dot notation property access is processed as follows at compile-time:

·         If ObjExpr is of type Any, any Name is permitted and the property access is of type Any.

·         Otherwise, if Name denotes a property member in the type of ObjExpr, the property access is of the type of that property.

·         Otherwise, the property access is invalid and a compile-time error occurs.

A bracket notation property access of the form

ObjExpr [ IndexExpr ]

where ObjExpr and IndexExpr are expressions, is used to access the property with the name computed by the index expression on the given object. A bracket notation property access is processed as follows at compile-time:

·         If IndexExpr is a string literal or a numeric literal and ObjExpr is of a type that has a property with the name given by that literal (converted to its string representation in the case of a numeric literal), the property access is of the type of that property.

·         Otherwise, if ObjExpr is of a type that has a numeric index signature and IndexExpr is of type Any, the Number primitive type, or an enum type, the property access is of the type of that index signature.

·         Otherwise, if ObjExpr is of a type that has a string index signature and IndexExpr is of type Any, the String or Number primitive type, or an enum type, the property access is of the type of that index signature.

·         Otherwise, if IndexExpr is of type Any, the String or Number primitive type, or an enum type, the property access is of type Any.

·         Otherwise, the property access is invalid and a compile-time error occurs.

4.11 The new Operator

A new operation has one of the following forms:

new ConstructExpr

new ConstructExpr ( Args )

where ConstructExpr is an expression and Args is an argument list. The first form is equivalent to supplying an empty argument list. ConstructExpr must be of type Any or of an object type with one or more construct or call signatures. The operation is processed as follows at compile-time:

·         If ConstructExpr is of type Any, Args can be any argument list and the result of the operation is of type Any.

·         If ConstructExpr is of an object type with one or more construct signatures, the expression is processed in the same manner as a function call, but using the construct signatures as the initial set of candidate signatures for overload resolution. The result type of the function call becomes the result type of the operation.

·         If ConstructExpr is of an object type with no construct signatures but one or more call signatures, the expression is processed as a function call. A compile-time error occurs if the result of the function call is not Void. The type of the result of the operation is Any.

4.12 Function Calls

Function calls are extended from JavaScript to optionally include type arguments.

Arguments:  ( Modified )
TypeArgumentsopt   
(   ArgumentListopt   )

A function call takes one of the forms

FuncExpr ( Args )

FuncExpr < TypeArgs > ( Args )

where FuncExpr is an expression of a function type or of type Any, TypeArgs is a type argument list, and Args is an argument list.

If FuncExpr is of type Any, or of an object type that has no call signatures but is a subtype of the Function interface, the call is an untyped function call. In an untyped function call no TypeArgs are permitted, Args can be any argument list, no contextual types are provided for the argument expressions, and the result is always of type Any.

If FuncExpr is of a function type, the call is a typed function call. TypeScript employs overload resolution in typed function calls in order to support functions with multiple call signatures. Furthermore, TypeScript may perform type argument inference to automatically determine type arguments in generic function calls.

4.12.1  Overload Resolution

The purpose of overload resolution in a function call is to ensure that at least one signature is applicable, to provide contextual types for the arguments, and to determine the result type of the function call, which could differ between the multiple applicable signatures. Overload resolution has no impact on the run-time behavior of a function call. Since JavaScript doesn’t support function overloading, all that matters at run-time is the name of the function.

The compile-time processing of a typed function call consists of the following steps:

·         First, a set of candidate signatures is constructed from the signatures in the function type.

o    A non-generic signature is a candidate when

§  the function call has no type arguments, and

§  the signature is applicable with respect to the argument list of the function call.

o    A generic signature is a candidate in a function call without type arguments when

§  type inference (section 4.12.2) succeeds in inferring a list of type arguments,

§  the inferred type arguments satisfy their constraints, and

§  once the inferred type arguments are substituted for their associated type parameters, the signature is applicable with respect to the argument list of the function call.

o    A generic signature is a candidate in a function call with type arguments when

§  The signature has the same number of type parameters as were supplied in the type argument list,

§  the type arguments satisfy their constraints, and

§  once the type arguments are substituted for their associated type parameters, the signature is applicable with respect to the argument list of the function call.

·         If the set of candidate signatures is empty, the function call is an error.

·         Otherwise, for every signature S in the set, if another signature is a better match for the argument list, S is eliminated from the set.

·         The result type of the call is the return type of the first remaining signature in the set in declaration order. For classes and interfaces, inherited signatures are considered to follow explicitly declared signatures in extends clause order.

A signature is said to be an applicable signature with respect to an argument list when

·         each non-optional parameter has a corresponding argument, and

·         each argument expression, contextually typed (section 4.18) by the corresponding parameter type in the signature, is of a type that is assignable to (section 3.8.3) that parameter type.

Given an argument list with a set of argument expressions { e1, e2, …, en } and two applicable signatures P and Q with parameter types { P1, P2, …, Pn } and { Q1, Q2, …, Qn }, P is a better match than Q when

·         for no argument, eX better matches QX than PX, and

·         for at least one argument, eX better matches PX than QX.

Given an expression e and two types T1 and T2, the better matching type is determined as follows:

·         If T1 and T2 are identical types, neither is a better match.

·         If e is a string literal and T1 is the corresponding string literal type, T1 is the better match.

·         If e is a string literal and T2 is the corresponding string literal type, T2 is the better match.

·         If the type of e is identical to T1, T1 is the better conversion.

·         If the type of e is identical to T2, T2 is the better conversion.

·         If T1 is a subtype of T2, T1 is the better match.

·         If T2 is a subtype of T1, T2 is the better match.

·         Otherwise, neither type is a better match.

4.12.2  Type Argument Inference

Given a signature < T1 , T2 , … , Tn > ( p1 : P1 , p2 : P2 , … , pm : Pm ), where each parameter type P references zero or more of the type parameters T, and an argument list ( e1 , e2 , … , em ), the task of type argument inference is to find a set of type arguments A1An to substitute for T1Tn such that the argument list becomes an applicable signature.

The inferred type argument for a particular type parameter is the best common type (section 3.10) of a set of candidate types. In order to compute candidate types, the argument list is processed as follows:

·         Initially all inferred type arguments are considered unfixed with an empty set of candidate types.

·         Proceeding from left to right, each argument expression e is inferentially typed by its corresponding parameter type P, possibly causing some inferred type arguments to become fixed, and candidate type inferences are made for unfixed inferred type arguments by relating the type computed for e to P.

The process of inferentially typing an expression e by a type T is the same as that of contextually typing e by T, with the following exceptions:

·         Where expressions contained within e would be contextually typed, they are instead inferentially typed.

·         Where a contextual type would be included in a candidate set for a best common type (such as when inferentially typing an object or array literal), an inferential type is not.

·         When a function expression is inferentially typed (section 4.9.3) and a type assigned to a parameter in that function expression references type parameters for which inferences are being made, the corresponding inferred type arguments to become fixed and no further candidate inferences are made for them.

Candidate inferences are made by relating a type S to a type T as follows:

·         If S is not assignable to T when type Any is substituted for all type parameters, no candidate inferences are made.

·         Otherwise, if T is a type parameter with an unfixed inferred type argument, S is added to the set of candidate types for that type argument.

·         Otherwise, if S and T are object types, then for each member M in T:

o    If M is a property and S contains a property N with the same name as M, inferences are made by relating the type of N to the type of M.

o    If M is a call or construct signature, then for each signature N in S that is assignable to M when type Any is substituted for all type parameters, candidate inferences are made by relating parameter types in N to parameter types in the same position in M, and by relating the return type of N to the return type of M.

o    If M is a string index signature, then for each string index signature N in S, inferences are made by relating the type of N to the type of M.

o    If M is a numeric index signature, then for each string or numeric index signature N in S, inferences are made by relating the type of N to the type of M.

TODO: Examples. Include example that demonstrates the inferred type is Any when the set of candidate inferences is empty.

4.12.3  Grammar Ambiguities

The inclusion of type arguments in the Arguments production (section 4.12) gives rise to certain ambiguities in the grammar for expressions. For example, the statement

f(g<A, B>(7));

could be interpreted as  a call to ‘f’ with two arguments, ‘g < A’ and ‘B > (7)’. Alternatively, it could be interpreted as a call to ‘f’ with one argument, which is a call to a generic function ‘g’ with two type arguments and one regular argument.

The grammar ambiguity is resolved as follows: In a context where one possible interpretation of a sequence of tokens is an Arguments production, if the initial sequence of tokens forms a syntactically correct TypeArguments production and is followed by a ‘(‘ token, then the sequence of tokens is processed an Arguments production, and any other possible interpretation is discarded. Otherwise, the sequence of tokens is not considered an Arguments production.

This rule means that the call to ‘f’ above is interpreted as a call with one argument, which is a call to a generic function ‘g’ with two type arguments and one regular argument. However, the statements

f(g < A, B > 7);

f(g < A, B > +(7));

are both interpreted as calls to ‘f’ with two arguments.

4.13 Type Assertions

TypeScript extends the JavaScript expression grammar with the ability to assert a type for an expression:

UnaryExpression:  ( Modified )

<   Type   >   UnaryExpression

A type assertion expression consists of a type enclosed in < and > followed by a unary expression. Type assertion expressions are purely a compile-time construct. Type assertions are not checked at run-time and have no impact on the emitted JavaScript (and therefore no run-time cost). The type and the enclosing < and > are simply removed from the generated code.

A type assertion expression of the form < T > e requires the type of e to be assignable to T or T to be assignable to the type of e, or otherwise a compile-time error occurs. The type of the result is T.

Type assertions check for assignment compatibility in both directions. Thus, type assertions allow type conversions that might be correct, but aren’t known to be correct. In the example

class Shape { ... }

class Circle extends Shape { ... }

function createShape(kind: string): Shape {
    if (kind === "circle") return new Circle();
    ...
}

var circle = <Circle> createShape("circle");

the type annotations indicate that the ‘createShape’ function might return a ‘Circle’ (because ‘Circle’ is a subtype of ‘Shape’), but isn’t known to do so (because its return type is ‘Shape’). Therefore, a type assertion is needed to treat the result as a ‘Circle’.

As mentioned above, type assertions are not checked at run-time and it is up to the programmer to guard against errors, for example using the instanceof operator:

var shape = createShape(shapeKind);
if (shape instanceof Circle) {
    var circle = <Circle> shape;
    ...
}

4.14 Unary Operators

The subsections that follow specify the compile-time processing rules of the unary operators. In general, if the operand of a unary operator does not meet the stated requirements, a compile-time error occurs and the result of the operation defaults to type Any in further processing.

4.14.1  The ++ and -- operators

These operators, in prefix or postfix form, require their operand to be of type Any, the Number primitive type, or an enum type, and classified as a reference (section 4.1). They produce a result of the Number primitive type.

4.14.2  The +, –, and ~ operators

These operators permit their operand to be of any type and produce a result of the Number primitive type.

The unary + operator can conveniently be used to convert a value of any type to the Number primitive type:

function getValue() { ... }

var n = +getValue();

The example above converts the result of ‘getValue()’ to a number if it isn’t a number already. The type inferred for ‘n’ is the Number primitive type regardless of the return type of ‘getValue’.

4.14.3  The ! operator

The ! operator permits its operand to be of any type and produces a result of the Boolean primitive type.

Two unary ! operators in sequence can conveniently be used to convert a value of any type to the Boolean primitive type:

function getValue() { ... }

var b = !!getValue();

The example above converts the result of ‘getValue()’ to a Boolean if it isn’t a Boolean already. The type inferred for ‘b’ is the Boolean primitive type regardless of the return type of ‘getValue’.

4.14.4  The delete Operator

The delete operator takes an operand of any type and produces a result of the Boolean primitive type.

4.14.5  The void Operator

The void operator takes an operand of any type and produces the value undefined. The type of the result is the Undefined type (3.2.6).

4.14.6  The typeof Operator

The typeof operator takes an operand of any type and produces a value of the String primitive type.

4.15 Binary Operators

The subsections that follow specify the compile-time processing rules of the binary operators. In general, if the operands of a binary operator do not meet the stated requirements, a compile-time error occurs and the result of the operation defaults to type any in further processing. Tables that summarize the compile-time processing rules for operands of the Any type, the Boolean, Number, and String primitive types, and all object types and type parameters (the Object column in the tables) are provided.

4.15.1  The *, /, %, –, <<, >>, >>>, &, ^, and | operators

These operators require their operands to be of type Any, the Number primitive type, or an enum type. Operands of an enum type are treated as having the primitive type Number. If one operand is the null or undefined value, it is treated as having the type of the other operand. The result is always of the Number primitive type.

 

Any

Boolean

Number

String

Object

Any

Number

 

Number

 

 

Boolean

 

 

 

 

 

Number

Number

 

Number

 

 

String

 

 

 

 

 

Object

 

 

 

 

 

4.15.2  The + operator

The binary + operator requires both operands to be of the Number primitive type or an enum type, or at least one of the operands to be of type Any or the String primitive type. Operands of an enum type are treated as having the primitive type Number. If one operand is the null or undefined value, it is treated as having the type of the other operand. If both operands are of the Number primitive type, the result is of the Number primitive type. If one or both operands are of the String primitive type, the result is of the String primitive type. Otherwise, the result is of type Any.

 

Any

Boolean

Number

String

Object

Any

Any

Any

Any

String

Any

Boolean

Any

 

 

String

 

Number

Any

 

Number

String

 

String

String

String

String

String

String

Object

Any

 

 

String

 

 

A value of any type can converted to the String primitive type by adding an empty string:

function getValue() { ... }

var s = getValue() + "";

The example above converts the result of ‘getValue()’ to a string if it isn’t a string already. The type inferred for ‘s’ is the String primitive type regardless of the return type of ‘getValue’.

4.15.3  The <, >, <=, >=, ==, !=, ===, and !== operators

These operators require one operand type to be identical to or a subtype of the other operand type. The result is always of the Boolean primitive type.

 

Any

Boolean

Number

String

Object

Any

Boolean

Boolean

Boolean

Boolean

Boolean

Boolean

Boolean

Boolean

 

 

 

Number

Boolean

 

Boolean

 

 

String

Boolean

 

 

Boolean

 

Object

Boolean

 

 

 

Boolean

4.15.4  The instanceof operator

The instanceof operator requires the left operand to be of type Any, an object type, or a type parameter type, and the right operand to be of type Any or a subtype of the ‘Function’ interface type. The result is always of the Boolean primitive type.

Note that object types containing one or more call or construct signatures are automatically subtypes of the ‘Function’ interface type, as described in section 3.3.

4.15.5  The in operator

The in operator requires the left operand to be of type Any or the String primitive type, and the right operand to be of type Any, an object type, or a type parameter type. The result is always of the Boolean primitive type.

4.15.6  The && operator

The && operator permits the operands to be of any type and produces a result of the same type as the second operand.

 

Any

Boolean

Number

String

Object

Any

Any

Boolean

Number

String

Object

Boolean

Any

Boolean

Number

String

Object

Number

Any

Boolean

Number

String

Object

String

Any

Boolean

Number

String

Object

Object

Any

Boolean

Number

String

Object

4.15.7  The || operator

The || operator permits the operands to be of any type and produces a result that is of the best common type (section 3.10) of the two operand types.

 

Any

Boolean

Number

String

Object

Any

Any

Any

Any

Any

Any

Boolean

Any

Boolean

{ }

{ }

{ }

Number

Any

{ }

Number

{ }

{ }

String

Any

{ }

{ }

String

{ }

Object

Any

{ }

{ }

{ }

Object

4.16 The Conditional Operator

In a conditional expression of the form

Cond ? Expr1 : Expr2

the Cond expression may be of any type, and Expr1 and Expr2 expressions must be of identical types or the type of one must be a subtype of the other. The result is of the best common type (section 3.10) of the two expression types.

4.17 Assignment Operators

An assignment of the form

VarExpr = ValueExpr

requires VarExpr to be classified as a reference (section 4.1). ValueExpr is contextually typed (section 4.18) by the type of VarExpr, and the type of ValueExpr must be assignable to (section 3.8.3) the type of VarExpr, or otherwise a compile-time error occurs. The result is a value with the type of ValueExpr.

A compound assignment of the form

VarExpr Operator= ValueExpr

where Operator= is of the compound assignment operators

*=   /=   %=   +=   -=   <<=   >>=   >>>=   &=   ^=   |=

is subject to the same requirements, and produces a value of the same type, as the corresponding non-compound operation. A compound assignment furthermore requires VarExpr to be classified as a reference (section 4.1) and the type of the non-compound operation to be assignable to the type of VarExpr.

4.18 Contextually Typed Expressions

In certain situations, parameter and return types of function expressions are automatically inferred from the contexts in which the function expressions occur. For example, given the declaration

var f: (s: string) => string;

the assignment

f = function(s) { return s.toLowerCase(); }

infers the type of the ‘s’ parameter to be the String primitive type even though there is no type annotation to that effect. The function expression is said to be contextually typed by the variable to which it is being assigned. Contextual typing occurs in the following situations:

·         In variable and member declarations with a type annotation and an initializer, the initializer expression is contextually typed by the type of the variable or property.

·         In assignment expressions, the right hand expression is contextually typed by the type of the left hand expression.

·         In typed function calls, argument expressions are contextually typed by their parameter types.

·         In return statements, if the containing function has a known return type, the expression is contextually typed by that return type. A function’s return type is known if the function includes a return type annotation or is itself contextually typed.

·         In contextually typed object literals, property assignments are contextually typed by their property types.

·         In contextually typed array literals, element expressions are contextually typed by the array element type.

Contextual typing of an expression e by a type T proceeds as follows:

·         If e is an ObjectLiteral and T is an object type, e is processed with the contextual type T, as described in section 4.5.

·         If e is an ArrayLiteral and T is an object type with a numeric index signature, e is processed with the contextual type T, as described in section 4.6.

·         If e is a FunctionExpression or ArrowFunctionExpression with no type parameters and no parameter or return type annotations, and T is an object type with exactly one call signature, e is processed with the contextual type T, as described in section 4.9.3.

·         Otherwise, e is processed without a contextual type.

The rules above require expressions be of the exact syntactic forms specified in order to be processed as contextually typed constructs. For example, given the declaration of the variable ‘f’ above, the assignment

f = s => s.toLowerCase();

causes the function expression to be contextually typed, inferring the String primitive type for ‘s’. However, simply enclosing the construct in parentheses

f = (s => s.toLowerCase());

causes the function expression to be processed without a contextual type, now inferring ‘s’ and the result of the function to be of type Any as no type annotations are present.

In the following example

interface EventObject {
    x: number;
    y: number;
}

interface EventHandlers {
    mousedown?: (event: EventObject) => void;
    mouseup?: (event: EventObject) => void;
    mousemove?: (event: EventObject) => void;
}

function setEventHandlers(handlers: EventHandlers) { ... }

setEventHandlers({
    mousedown: e => { startTracking(e.x, e.y); },
    mouseup: e => { endTracking(); }
});

the object literal passed to ‘setEventHandlers’ is contextually typed to the ‘EventHandlers’ type. This causes the two property assignments to be contextually typed to the unnamed function type ‘(event: EventObject) => void’, which in turn causes the ‘e’ parameters in the arrow function expressions to automatically be typed as ‘EventObject’.

 


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.