Skip to content
This repository has been archived by the owner on May 25, 2023. It is now read-only.

Latest commit

 

History

History
224 lines (169 loc) · 8.24 KB

ch06.md

File metadata and controls

224 lines (169 loc) · 8.24 KB

6 Functions

TypeScript extends JavaScript functions to include type parameters, parameter and return type annotations, overloads, default parameter values, and rest parameters.

6.1 Function Declarations

Function declarations consist of an optional set of function overloads followed by an actual function implementation.

FunctionDeclaration: ( Modified )
    FunctionOverloads(opt) FunctionImplementation

FunctionOverloads:
    FunctionOverload
    FunctionOverloads FunctionOverload

FunctionOverload:
    function Identifier CallSignature ;

FunctionImplementation:
    function Identifier CallSignature { FunctionBody }

A function declaration introduces a function with the given name in the containing declaration space. Function overloads, if present, must specify the same name as the function implementation. If a function declaration includes overloads, the overloads determine the call signatures of the type given to the function object and the function implementation signature must be assignable to that type. Otherwise, the function implementation itself determines the call signature. Function overloads have no other effect on a function declaration.

6.2 Function Overloads

Function overloads allow a more accurate specification of the patterns of invocation supported by a function than is possible with a single signature. The compile-time processing of a call to an overloaded function chooses the best candidate overload for the particular arguments and the return type of that overload becomes the result type the function call expression. Thus, using overloads it is possible to statically describe the manner in which a function's return type varies based on its arguments. Overload resolution in function calls is described further in section 4.12.

Function overloads are purely a compile-time construct. They have no impact on the emitted JavaScript and thus no run-time cost.

The parameter list of a function overload cannot specify default values for parameters. In other words, an overload may use only the ? form when specifying optional parameters.

The following is an example of a function with overloads.

function attr(name: string): string;
function attr(name: string, value: string): Accessor;
function attr(map: any): Accessor;
function attr(nameOrMap: any, value?: string): any {
    if (nameOrMap && typeof nameOrMap === "string") {
        // handle string case
    }
    else {
        // handle map case
    }
}

Note that each overload and the final implementation specify the same identifier. The type of the local variable attr introduced by this declaration is

var attr: {
    (name: string): string;
    (name: string, value: string): Accessor;
    (map: any): Accessor;
};

Note that the signature of the actual function implementation is not included in the type.

6.3 Function Implementations

A function implementation without a return type annotation is said to be an implicitly typed function. The return type of an implicitly typed function f is inferred from its function body as follows:

  • If there are no return statements with expressions in f's function body, the inferred return type is Void.
  • Otherwise, if f's function body directly references f or references any implicitly typed functions that through this same analysis reference f, the inferred return type is Any.
  • Otherwise, the inferred return type is the widened form (section 3.9) of the best common type (section 3.10) of the types of the return statement expression in the function body, ignoring return statements with no expressions. A compile-time error occurs if the best common type isn't one of the return statement expression types (i.e. if the best common type is an empty type).

In the example

function f(x: number) {
    if (x <= 0) return x;
    return g(x);
}

function g(x: number) {
return f(x - 1);
}

the inferred return type for f and g is Any because the functions reference themselves through a cycle with no return type annotations. Adding an explicit return type number to either breaks the cycle and causes the return type number to be inferred for the other.

An explicitly typed function whose return type isn't the Void or the Any type must have at least one return statement somewhere in its body. An exception to this rule is if the function implementation consists of a single throw statement.

The type of this in a function implementation is the Any type.

In the signature of a function implementation, a parameter can be marked optional by following it with an initializer. When a parameter declaration includes both a type annotation and an initializer, the initializer expression is contextually typed (section 4.19) by the stated type and must be assignable to the stated type, or otherwise a compile-time error occurs. When a parameter declaration has no type annotation but includes an initializer, the type of the parameter is the widened form (section 3.9) of the type of the initializer expression.

Initializer expressions are evaluated in the scope of the function body but are not permitted to reference local variables and are only permitted to access parameters that are declared to the left of the parameter they initialize.

For each parameter with an initializer, a statement that substitutes the default value for an omitted argument is included in the generated JavaScript, as described in section 6.5. The example

function strange(x: number, y = x * 2, z = x + y) {
    return z;
}

generates JavaScript that is equivalent to

function strange(x, y, z) {
    if (typeof y === "undefined") { y = x * 2; }
    if (typeof z === "undefined") { z = x + y; }
    return z;
}

In the example

var x = 1;
function f(a = x) {
    var x = "hello";
}

the local variable x is in scope in the parameter initializer (thus hiding the outer x), but it is an error to reference it because it will always be uninitialized at the time the parameter initializer is evaluated.

6.4 Generic Functions

A function implementation may include type parameters in its signature (section 3.7.2.1) and is then called a generic function. Type parameters provide a mechanism for expressing relationships between parameter and return types in call operations. Type parameters have no run-time representation—they are purely a compile-time construct.

Type parameters declared in the signature of a function implementation are in scope in the signature and body of that function implementation.

The following is an example of a generic function:

interface Comparable {
    localeCompare(other: any): number;
}

function compare<T extends Comparable>(x: T, y: T): number {
    if (x == null) return y == null ? 0 : -1;
    if (y == null) return 1;
    return x.localeCompare(y);
}

Note that the x and y parameters are known to be subtypes of the constraint Comparable and therefore have a compareTo member. This is described further in section 3.4.1.

The type arguments of a call to a generic function may be explicitly specified in a call operation or may, when possible, be inferred (section 4.12.2) from the types of the regular arguments in the call. In the example

class Person {
    name: string;
    localeCompare(other: Person) {
        return compare(this.name, other.name);
    }
}

the type argument to compare is automatically inferred to be the String type because the two arguments are strings.

6.5 Code Generation

A function declaration generates JavaScript code that is equivalent to:

function <FunctionName>(<FunctionParameters>) {
    <DefaultValueAssignments>
    <FunctionStatements>
}

FunctionName is the name of the function (or nothing in the case of a function expression).

FunctionParameters is a comma separated list of the function's parameter names.

DefaultValueAssignments is a sequence of default property value assignments, one for each parameter with a default value, in the order they are declared, of the form

if (typeof <Parameter> === "undefined") { <Parameter> = <Default>; }

where Parameter is the parameter name and Default is the default value expression.

FunctionStatements is the code generated for the statements specified in the function body.