TypeScript学习笔记一:函数(译)

函数

  Tsjs扩展了类型参数、参数和返回类型注释、重载、默认参数值和可变参数数组。

6.1 函数声明

  在ts中,函数声明在重载时可以省略函数体。

  FunctionDeclaration:  ( Modified )
    function   BindingIdentifieropt   CallSignature   {   FunctionBody   }
    function   BindingIdentifieropt   CallSignature   ;

  函数声明在包含的声明空间中引入一个函数类型的命名值。当函数声明发生在一个默认导出声明中时,绑定标识符是可选的。

  指定函数体的函数声明被称为函数实现,否则被称为函数重载。一个函数可以有多个重载,但是一个函数可以至少有一个实现。所有的同名函数声明必须指定相同的修饰符(如同样的declare,exportdefault)。

  如果一个函数有重载声明,那么,此重载声明决定函数对象的类型的调用签名,函数实现签名必须赋予此类型,否则,函数实现自身决定调用签名。

  当一个函数同时具有重载和实现时,重载必须位于实现之前并且所有的声明必须连续而不穿插其他元素。

6.2 函数重载

  调用重载函数是在编译时处理的,它在候选的重载函数中挑选具有合适的参数和返回值的重载函数,然后提供给函数调用表达式。因此,运用重载可以静态地描述返回类型的多样化。

  函数重载是纯编译时结构。它对声明的js代码无任何影响,因此无运行时开销。

  函数重载的参数列表不能指定默认值。换言之,一个重载只能用“?”形式来指定可选参数。

  如下例:

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

  所有的重载和实现都指定了同一名字。此声明引入了一个本地变量“attr“的类型:

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

  需要注意的是,此类型不包含具体的函数实现签名。

6.3 函数实现

  无返回类型注释的函数实现被称为“隐式类型函数”。隐式类型函数“f"的返回类型是通过函数体来推断的:

    • 如果表达式无返回语句,那么返回类型为“Void”类型。
    • 否则,如果”f“的函数体直接引用”f“或通过引用分析来直接引用任何隐式类型的函数,那么返回类型为”Any“类型。
    • 否则,如果”f“是一个上下文类型函数表达式。那么返回类型为返回表达式语句的联合类型。
    • 否则,返回类型为返回表达式语句的第一个类型,此类型是每个其他类型的子类型。

  如下例:

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

  ”f“和”g”返回类型都是“Any“,因为它们互相引用对方,而它们各自都无返回类型注释。当为其中一个函数添加了显示的”number“返回类型来跳出循环语句时,它们的返回类型都变成了”number“类型。

  返回类型不是“Void“或”Any“的显式类型的函数必须至少有一个返回语句。但是如果函数实现包含了一个”throw“语句时则例外。

  函数实现中“this“的类型是”Any“类型。

  在函数实现签名中,参数可以通过初始化的方式来标记为可选。当参数声明同时包含类型注释和参数化时,初始化表达式通过上下文确定类型。当参数声明只包含初始化时,参数的类型是初始化类型的扩展形式。

  当输出目标是ECMAScript 3 或5时,每一个初始化都生成为具有默认值的表达式,如:

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

  生成的js代码为:

function strange(x, y, z) {
    if (y === void 0) { y = x * 2; }
    if (z === void 0) { z = x + y; }
    return z;
}

6.4 析构参数声明

  可以指定绑定模式的参数声明被称为析构参数声明。如同析构变量声明一样,析构参数声明引入零个或多个本地命名参数并为其赋值,这些值是从属性、对象的元素或作为参数传递的数组中提取而得。

  析构参数声明中引入的本地参数类型的决定方式与析构变量声明中引入的本地变量类型的决定方式类似,除非其类型"T"由以下方式决定:

    • 如果声明包含类型注释,那么”T“就是此类型。
    • 如果声明发生在一个上下文签名可用的函数表达式中,”T“类型从上下文签名中获取而来。
    • 否则,如果声明包含初始化表达式,那么”T“是初始化表达式类型的扩展形式。
    • 否则,如果声明指定了一个绑定模式,”T“就是绑定模式的隐含类型。
    • 否则,如果参数是可变参数,”T“就是”Any[]“类型。
    • 否则,”T“是”Any“类型。  

 当输出目标是ECMAScript 2015或更高时,除非移除了可选类型注释,析构参数声明在生成的js代码中保留不变。当输出目标是ECMAScript 3 或5时,析构参数声明被重写为本地变量声明。

  如下例:

 

function drawText({ text = "", location: [x, y] = [0, 0], bold = false }) {
    // Draw text
}

 

  声明了一个拥有一个如下类型的参数:

{ text?: string; location?: [number, number]; bold?: boolean; }

  当输出目标是ECMAScript 3 或5时,函数被重写为:

function drawText(_a) {
    var _b = _a.text,
        text = _b === void 0 ? "" : _b,
        _c = _a.location,
        _d = _c === void 0 ? [0, 0] : _c,
        x = _d[0],
        y = _d[1],
        _e = _a.bold,
        bold = _e === void 0 ? false : _e;
    // Draw text
}

  在个体绑定模式中,析构参数声明不能有类型注释,因为这样将会与已存在的对象成员类型相冲突。类型注释必须写在参数声明的顶层。如:

interface DrawTextInfo {
    text?: string;
    location?: [number, number];
    bold?: boolean;
}
function drawText({ text, location: [x, y], bold }: DrawTextInfo) {
    // Draw text
}

6.5 泛型函数

  包含类型参数的函数签名称为泛型函数。类型参数提供了一种机制,它可以表示参数与调用操作时的返回类型的关系。类型参数是纯编译时结构,无运行时表现。

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

  “x"和”y"参数被认为是“Comparable”约束的子类型,它具有一个“compateTo”成员。

  调用泛型函数时,类型参数可以显式指定,也可以通过参数的类型推断出来。如下例:

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

  “compare”的类型参数被自动引用为“String”类型,因为两个参数都是“String”类型。

6.6 代码生成

  函数声明生成以下格式的js代码:

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

  “FunctionName”是函数名称。“FunctionParameters”是函数参数列表。

  “DefaultValueAssignments”是默认属性赋值表达式列表,格式如下:

if (<Parameter> === void 0) { <Parameter> = <Default>; }

  “FunctionStatements”是生成的函数体代码。

posted @ 2016-01-11 19:16  leeberg  阅读(449)  评论(0)    收藏  举报