Skip to content
Permalink
Branch: master
Find file 复制路径
Find file 复制路径
@mayn mayn fix spelling errors f30e8a2 一月28,2019
7 contributors

Users who have contributed to this file

@ahejlsberg @masaeedu @zhongsp @sanket0896 @mayn @andfaulkner @surlymrz
6739行(4736坑) 365 KB

TypeScript Language Specification

版本1.8

2016年1月


Microsoft自2012年10月1日起根据Open Web Foundation最终规范协议版本1.0(" OWF 1.0")提供此规范.OWF 1.0可以从http://www.openwebfoundation.org/legal/the-owf获得. -1-0-agreements / owfa-1-0 .

TypeScript是Microsoft Corporation的商标.


Table of Contents


1 Introduction

JavaScript applications such as web e-mail, maps, document editing, and collaboration tools are becoming an increasingly important part of the everyday computing. We designed TypeScript to meet the needs of the JavaScript programming teams that build and maintain large JavaScript programs. TypeScript helps programming teams to define interfaces between software components and to gain insight into the behavior of existing JavaScript libraries. TypeScript also enables teams to reduce naming conflicts by organizing their code into dynamically-loadable modules. TypeScript's optional type system enables JavaScript programmers to use highly-productive development tools and practices: static checking, symbol-based navigation, statement completion, and code refactoring.

TypeScript is a syntactic sugar for JavaScript. TypeScript syntax is a superset of ECMAScript 2015 (ES2015) syntax. Every JavaScript program is also a TypeScript program. The TypeScript compiler performs only file-local transformations on TypeScript programs and does not re-order variables declared in TypeScript. This leads to JavaScript output that closely matches the TypeScript input. TypeScript does not transform variable names, making tractable the direct debugging of emitted JavaScript. TypeScript optionally provides source maps, enabling source-level debugging. TypeScript tools typically emit JavaScript upon file save, preserving the test, edit, refresh cycle commonly used in JavaScript development.

TypeScript syntax includes all features of ECMAScript 2015, including classes and modules, and provides the ability to translate these features into ECMAScript 3 or 5 compliant code.

Classes enable programmers to express common object-oriented patterns in a standard way, making features like inheritance more readable and interoperable. Modules enable programmers to organize their code into components while avoiding naming conflicts. The TypeScript compiler provides module code generation options that support either static or dynamic loading of module contents.

TypeScript also provides to JavaScript programmers a system of optional type annotations. These type annotations are like the JSDoc comments found in the Closure system, but in TypeScript they are integrated directly into the language syntax. This integration makes the code more readable and reduces the maintenance cost of synchronizing type annotations with their corresponding variables.

The TypeScript type system enables programmers to express limits on the capabilities of JavaScript objects, and to use tools that enforce these limits. To minimize the number of annotations needed for tools to become useful, the TypeScript type system makes extensive use of type inference. For example, from the following statement, TypeScript will infer that the variable 'i' has the type number.

var i = 0;

TypeScript will infer from the following function definition that the function f has return type string.

function f() {  
    return "hello";  
}

To benefit from this inference, a programmer can use the TypeScript language service. For example, a code editor can incorporate the TypeScript language service and use the service to find the members of a string object as in the following screenshot.

  

In this example, the programmer benefits from type inference without providing type annotations. Some beneficial tools, however, do require the programmer to provide type annotations. In TypeScript, we can express a parameter requirement as in the following code fragment.

function f(s: string) {  
    return s;  
}

f({});       // Error  
f("hello");  // Ok

This optional type annotation on the parameter 's' lets the TypeScript type checker know that the programmer expects parameter 's' to be of type 'string'. Within the body of function 'f', tools can assume 's' is of type 'string' and provide operator type checking and member completion consistent with this assumption. Tools can also signal an error on the first call to 'f', because 'f' expects a string, not an object, as its parameter. For the function 'f', the TypeScript compiler will emit the following JavaScript code:

function f(s) {  
    return s;  
}

In the JavaScript output, all type annotations have been erased. In general, TypeScript erases all type information before emitting JavaScript.

1.1 Ambient Declarations

An ambient declaration introduces a variable into a TypeScript scope, but has zero impact on the emitted JavaScript program. Programmers can use ambient declarations to tell the TypeScript compiler that some other component will supply a variable. For example, by default the TypeScript compiler will print an error for uses of undefined variables. To add some of the common variables defined by browsers, a TypeScript programmer can use ambient declarations. The following example declares the 'document' object supplied by browsers. Because the declaration does not specify a type, the type 'any' is inferred. The type 'any' means that a tool can assume nothing about the shape or behavior of the document object. Some of the examples below will illustrate how programmers can use types to further characterize the expected behavior of an object.

declare var document;  
document.title = "Hello";  // Ok because document has been declared

In the case of 'document', the TypeScript compiler automatically supplies a declaration, because TypeScript by default includes a file 'lib.d.ts' that provides interface declarations for the built-in JavaScript library as well as the Document Object Model.

The TypeScript compiler does not include by default an interface for jQuery, so to use jQuery, a programmer could supply a declaration such as:

declare var $;

1.3 提供了一个更广泛的示例,说明程序员如何为jQuery和其他库添加类型信息.

1.2 Function Types

Function expressions are a powerful feature of JavaScript. They enable function definitions to create closures: functions that capture information from the lexical scope surrounding the function's definition. Closures are currently JavaScript's only way of enforcing data encapsulation. By capturing and using environment variables, a closure can retain information that cannot be accessed from outside the closure. JavaScript programmers often use closures to express event handlers and other asynchronous callbacks, in which another software component, such as the DOM, will call back into JavaScript through a handler function.

TypeScript function types make it possible for programmers to express the expected signature of a function. A function signature is a sequence of parameter types plus a return type. The following example uses function types to express the callback signature requirements of an asynchronous voting mechanism.

function vote(candidate: string, callback: (result: string) => any) {  
   // ...  
}

vote("BigPig",  
     function(result: string) {  
         if (result === "BigPig") {  
            // ...  
         }  
     }  
);

In this example, the second parameter to 'vote' has the function type

(result: string) => any

which means the second parameter is a function returning type 'any' that has a single parameter of type 'string' named 'result'.

3.9.2 提供了有关函数类型的其他信息.

1.3 Object Types

TypeScript programmers use object types to declare their expectations of object behavior. The following code uses an object type literal to specify the return type of the 'MakePoint' function.

var MakePoint: () => {  
    x: number; y: number;  
};

Programmers can give names to object types; we call named object types interfaces. For example, in the following code, an interface declares one required field (name) and one optional field (favoriteColor).

interface Friend {  
    name: string;  
    favoriteColor?: string;  
}

function add(friend: Friend) {  
    var name = friend.name;  
}

add({ name: "Fred" });  // Ok  
add({ favoriteColor: "blue" });  // Error, name required  
add({ name: "Jill", favoriteColor: "green" });  // Ok

TypeScript object types model the diversity of behaviors that a JavaScript object can exhibit. For example, the jQuery library defines an object, '$', that has methods, such as 'get' (which sends an Ajax message), and fields, such as 'browser' (which gives browser vendor information). However, jQuery clients can also call '$' as a function. The behavior of this function depends on the type of parameters passed to the function.

The following code fragment captures a small subset of jQuery behavior, just enough to use jQuery in a simple way.

interface JQuery {  
    text(content: string);  
}  
  
interface JQueryStatic {  
    get(url: string, callback: (data: string) => any);     
    (query: string): JQuery;  
}

declare var $: JQueryStatic;

$.get("http://mysite.org/divContent",  
      function (data: string) {  
          $("div").text(data);  
      }  
);

The 'JQueryStatic' interface references another interface: 'JQuery'. This interface represents a collection of one or more DOM elements. The jQuery library can perform many operations on such a collection, but in this example the jQuery client only needs to know that it can set the text content of each jQuery element in a collection by passing a string to the 'text' method. The 'JQueryStatic' interface also contains a method, 'get', that performs an Ajax get operation on the provided URL and arranges to invoke the provided callback upon receipt of a response.

Finally, the 'JQueryStatic' interface contains a bare function signature

(query: string): JQuery;

The bare signature indicates that instances of the interface are callable. This example illustrates that TypeScript function types are just special cases of TypeScript object types. Specifically, function types are object types that contain one or more call signatures. For this reason we can write any function type as an object type literal. The following example uses both forms to describe the same type.

var f: { (): string; };  
var sameType: () => string = f;     // Ok  
var nope: () => number = sameType;  // Error: type mismatch

We mentioned above that the '$' function behaves differently depending on the type of its parameter. So far, our jQuery typing only captures one of these behaviors: return an object of type 'JQuery' when passed a string. To specify multiple behaviors, TypeScript supports overloading of function signatures in object types. For example, we can add an additional call signature to the 'JQueryStatic' interface.

(ready: () => any): any;

This signature denotes that a function may be passed as the parameter of the '$' function. When a function is passed to '$', the jQuery library will invoke that function when a DOM document is ready. Because TypeScript supports overloading, tools can use TypeScript to show all available function signatures with their documentation tips and to give the correct documentation once a function has been called with a particular signature.

A typical client would not need to add any additional typing but could just use a community-supplied typing to discover (through statement completion with documentation tips) and verify (through static checking) correct use of the library, as in the following screenshot.

  

3.3 提供了有关对象类型的其他信息.

1.4 Structural Subtyping

Object types are compared structurally. For example, in the code fragment below, class 'CPoint' matches interface 'Point' because 'CPoint' has all of the required members of 'Point'. A class may optionally declare that it implements an interface, so that the compiler will check the declaration for structural compatibility. The example also illustrates that an object type can match the type inferred from an object literal, as long as the object literal supplies all of the required members.

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

function getX(p: Point) {  
    return p.x;  
}

class CPoint {  
    x: number;  
    y: number;  
    constructor(x: number,  y: number) {  
        this.x = x;  
        this.y = y;  
    }  
}

getX(new CPoint(0, 0));  // Ok, fields match

getX({ x: 0, y: 0, color: "red" });  // Extra fields Ok

getX({ x: 0 });  // Error: supplied parameter does not match

有关类型比较的更多信息, 请参见第 3.11 .

1.5 Contextual Typing

Ordinarily, TypeScript type inference proceeds "bottom-up": from the leaves of an expression tree to its root. In the following example, TypeScript infers 'number' as the return type of the function 'mul' by flowing type information bottom up in the return expression.

function mul(a: number, b: number) {  
    return a * b;  
}

For variables and parameters without a type annotation or a default value, TypeScript infers type 'any', ensuring that compilers do not need non-local information about a function's call sites to infer the function's return type. Generally, this bottom-up approach provides programmers with a clear intuition about the flow of type information.

However, in some limited contexts, inference proceeds "top-down" from the context of an expression. Where this happens, it is called contextual typing. Contextual typing helps tools provide excellent information when a programmer is using a type but may not know all of the details of the type. For example, in the jQuery example, above, the programmer supplies a function expression as the second parameter to the 'get' method. During typing of that expression, tools can assume that the type of the function expression is as given in the 'get' signature and can provide a template that includes parameter names and types.

$.get("http://mysite.org/divContent",  
      function (data) {  
          $("div").text(data);  // TypeScript infers data is a string  
      }  
);

Contextual typing is also useful for writing out object literals. As the programmer types the object literal, the contextual type provides information that enables tools to provide completion for object member names.

Section 4.23 provides additional information about contextually typed expressions.

1.6 Classes

JavaScript practice has two very common design patterns: the module pattern and the class pattern. Roughly speaking, the module pattern uses closures to hide names and to encapsulate private data, while the class pattern uses prototype chains to implement many variations on object-oriented inheritance mechanisms. Libraries such as 'prototype.js' are typical of this practice. TypeScript's namespaces are a formalization of the module pattern. (The term "module pattern" is somewhat unfortunate now that ECMAScript 2015 formally supports modules in a manner different from what the module pattern prescribes. For this reason, TypeScript uses the term "namespace" for its formalization of the module pattern.)

This section and the namespace section below will show how TypeScript emits consistent, idiomatic JavaScript when emitting ECMAScript 3 or 5 compliant code for classes and namespaces. The goal of TypeScript's translation is to emit exactly what a programmer would type when implementing a class or namespace unaided by a tool. This section will also describe how TypeScript infers a type for each class declaration. We'll start with a simple BankAccount class.

class BankAccount {  
    balance = 0;  
    deposit(credit: number) {  
        this.balance += credit;  
        return this.balance;  
    }  
}  

This class generates the following JavaScript code.

var BankAccount = (function () {  
    function BankAccount() {  
        this.balance = 0;  
    }  
    BankAccount.prototype.deposit = function(credit) {  
        this.balance += credit;  
        return this.balance;  
    };  
    return BankAccount;  
})();

This TypeScript class declaration creates a variable named 'BankAccount' whose value is the constructor function for 'BankAccount' instances. This declaration also creates an instance type of the same name. If we were to write this type as an interface it would look like the following.

interface BankAccount {  
    balance: number;  
    deposit(credit: number): number;  
}

If we were to write out the function type declaration for the 'BankAccount' constructor variable, it would have the following form.

var BankAccount: new() => BankAccount;

The function signature is prefixed with the keyword 'new' indicating that the 'BankAccount' function must be called as a constructor. It is possible for a function's type to have both call and constructor signatures. For example, the type of the built-in JavaScript Date object includes both kinds of signatures.

If we want to start our bank account with an initial balance, we can add to the 'BankAccount' class a constructor declaration.

class BankAccount {  
    balance: number;  
    constructor(initially: number) {  
        this.balance = initially;  
    }  
    deposit(credit: number) {  
        this.balance += credit;  
        return this.balance;  
    }  
}

This version of the 'BankAccount' class requires us to introduce a constructor parameter and then assign it to the 'balance' field. To simplify this common case, TypeScript accepts the following shorthand syntax.

class BankAccount {  
    constructor(public balance: number) {  
    }  
    deposit(credit: number) {  
        this.balance += credit;  
        return this.balance;  
    }  
}

The 'public' keyword denotes that the constructor parameter is to be retained as a field. Public is the default accessibility for class members, but a programmer can also specify private or protected accessibility for a class member. Accessibility is a design-time construct; it is enforced during static type checking but does not imply any runtime enforcement.

TypeScript classes also support inheritance, as in the following example.* *

class CheckingAccount extends BankAccount {  
    constructor(balance: number) {  
        super(balance);  
    }  
    writeCheck(debit: number) {  
        this.balance -= debit;  
    }  
}

In this example, the class 'CheckingAccount' derives from class 'BankAccount'. The constructor for 'CheckingAccount' calls the constructor for class 'BankAccount' using the 'super' keyword. In the emitted JavaScript code, the prototype of 'CheckingAccount' will chain to the prototype of 'BankAccount'.

TypeScript classes may also specify static members. Static class members become properties of the class constructor.

8 提供了有关类的其他信息.

1.7 Enum Types

TypeScript enables programmers to summarize a set of numeric constants as an enum type. The example below creates an enum type to represent operators in a calculator application.

const enum Operator {  
    ADD,  
    DIV,  
    MUL,  
    SUB  
}

function compute(op: Operator, a: number, b: number) {  
    console.log("the operator is" + Operator[op]);  
    // ...  
}

在此示例中,计算功能使用枚举类型的功能记录运算符" op":从枚举值(op)到与该值对应的字符串的反向映射. 例如,"运算符"的声明会自动将从零开始的整数分配给列出的枚举成员. 9 介绍了程序员还可以如何将整数显式分配给枚举成员,以及如何使用任何字符串来命名枚举成员.

当使用const修饰符声明枚举时,TypeScript编译器将为该枚举成员发出与该成员的分配值相对应的JavaScript常量(带有注释). 这样可以提高许多JavaScript引擎的性能.

例如,"计算"功能可能包含如下的switch语句.

switch (op) {  
    case Operator.ADD:  
        // execute add  
        break;  
    case Operator.DIV:  
        // execute div  
        break;  
    // ...  
}

对于此switch语句,编译器将生成以下代码.

switch (op) {  
    case 0 /* Operator.ADD */:  
        // execute add  
        break;  
    case 1 /* Operator.DIV */:  
        // execute div  
        break;  
    // ...  
}

JavaScript实现可以使用这些显式常量为该switch语句生成有效的代码,例如,通过构建一个由case值索引的跳转表.

1.8 Overloading on String Parameters

An important goal of TypeScript is to provide accurate and straightforward types for existing JavaScript programming patterns. To that end, TypeScript includes generic types, discussed in the next section, and overloading on string parameters, the topic of this section.

JavaScript programming interfaces often include functions whose behavior is discriminated by a string constant passed to the function. The Document Object Model makes heavy use of this pattern. For example, the following screenshot shows that the 'createElement' method of the 'document' object has multiple signatures, some of which identify the types returned when specific strings are passed into the method.

  

The following code fragment uses this feature. Because the 'span' variable is inferred to have the type 'HTMLSpanElement', the code can reference without static error the 'isMultiline' property of 'span'.

var span = document.createElement("span");  
span.isMultiLine = false;  // OK: HTMLSpanElement has isMultiline property

In the following screenshot, a programming tool combines information from overloading on string parameters with contextual typing to infer that the type of the variable 'e' is 'MouseEvent' and that therefore 'e' has a 'clientX' property.

  

3.9.2.4 提供了有关如何在函数签名中使用字符串文字的详细信息.

1.9 Generic Types and Functions

Like overloading on string parameters, generic types make it easier for TypeScript to accurately capture the behavior of JavaScript libraries. Because they enable type information to flow from client code, through library code, and back into client code, generic types may do more than any other TypeScript feature to support detailed API descriptions.

To illustrate this, let's take a look at part of the TypeScript interface for the built-in JavaScript array type. You can find this interface in the 'lib.d.ts' file that accompanies a TypeScript distribution.

interface Array<T> {  
    reverse(): T[];  
    sort(compareFn?: (a: T, b: T) => number): T[];  
    // ...   
}

Interface definitions, like the one above, can have one or more type parameters. In this case the 'Array' interface has a single parameter, 'T', that defines the element type for the array. The 'reverse' method returns an array with the same element type. The sort method takes an optional parameter, 'compareFn', whose type is a function that takes two parameters of type 'T' and returns a number. Finally, sort returns an array with element type 'T'.

Functions can also have generic parameters. For example, the array interface contains a 'map' method, defined as follows:

map<U>(func: (value: T, index: number, array: T[]) => U, thisArg?: any): U[];

The map method, invoked on an array 'a' with element type 'T', will apply function 'func' to each element of 'a', returning a value of type 'U'.

The TypeScript compiler can often infer generic method parameters, making it unnecessary for the programmer to explicitly provide them. In the following example, the compiler infers that parameter 'U' of the map method has type 'string', because the function passed to map returns a string.

function numberToString(a: number[]) {  
    var stringArray = a.map(v => v.toString());  
    return stringArray;  
}

The compiler infers in this example that the 'numberToString' function returns an array of strings.

In TypeScript, classes can also have type parameters. The following code declares a class that implements a linked list of items of type 'T'. This code illustrates how programmers can constrain type parameters to extend a specific type. In this case, the items on the list must extend the type 'NamedItem'. This enables the programmer to implement the 'log' function, which logs the name of the item.

interface NamedItem {  
    name: string;  
}

class List<T extends NamedItem> {  
    next: List<T> = null;

    constructor(public item: T) {  
    }

    insertAfter(item: T) {  
        var temp = this.next;  
        this.next = new List(item);  
        this.next.next = temp;  
    }

    log() {  
        console.log(this.item.name);  
    }

    // ...  
}

3.7 提供了有关泛型类型的更多信息.

1.10 Namespaces

Classes and interfaces support large-scale JavaScript development by providing a mechanism for describing how to use a software component that can be separated from that component's implementation. TypeScript enforces encapsulation of implementation in classes at design time (by restricting use of private and protected members), but cannot enforce encapsulation at runtime because all object properties are accessible at runtime. Future versions of JavaScript may provide private names which would enable runtime enforcement of private and protected members.

In JavaScript, a very common way to enforce encapsulation at runtime is to use the module pattern: encapsulate private fields and methods using closure variables. The module pattern is a natural way to provide organizational structure and dynamic loading options by drawing a boundary around a software component. The module pattern can also provide the ability to introduce namespaces, avoiding use of the global namespace for most software components.

The following example illustrates the JavaScript module pattern.

(function(exports) {  
    var key = generateSecretKey();  
    function sendMessage(message) {  
        sendSecureMessage(message, key);  
    }  
    exports.sendMessage = sendMessage;  
})(MessageModule);

This example illustrates the two essential elements of the module pattern: a module closure and a module object. The module closure is a function that encapsulates the module's implementation, in this case the variable 'key' and the function 'sendMessage'. The module object contains the exported variables and functions of the module. Simple modules may create and return the module object. The module above takes the module object as a parameter, 'exports', and adds the 'sendMessage' property to the module object. This augmentation approach simplifies dynamic loading of modules and also supports separation of module code into multiple files.

The example assumes that an outer lexical scope defines the functions 'generateSecretKey' and 'sendSecureMessage'; it also assumes that the outer scope has assigned the module object to the variable 'MessageModule'.

TypeScript namespaces provide a mechanism for succinctly expressing the module pattern. In TypeScript, programmers can combine the module pattern with the class pattern by nesting namespaces and classes within an outer namespace.

The following example shows the definition and use of a simple namespace.

namespace M {  
    var s = "hello";  
    export function f() {  
        return s;  
    }  
}

M.f();  
M.s;  // Error, s is not exported

In this example, variable 's' is a private feature of the namespace, but function 'f' is exported from the namespace and accessible to code outside of the namespace. If we were to describe the effect of namespace 'M' in terms of interfaces and variables, we would write

interface M {  
    f(): string;  
}

var M: M;

接口" M"概括了名称空间" M"的外部可见行为. 在此示例中,我们可以为接口使用与初始化变量相同的名称,因为在TypeScript中,类型名和变量名不会冲突:每个词法作用域都包含变量声明空间和类型声明空间(有关更多详细信息, 请参见第 2.3 ). .

TypeScript编译器为名称空间发出以下JavaScript代码:

var M;  
(function(M) {  
    var s = "hello";  
    function f() {  
        return s;  
    }  
    M.f = f;  
})(M || (M = {}));

在这种情况下,编译器假定名称空间对象驻留在全局变量" M"中,该变量可能已初始化或尚未初始化为所需的名称空间对象.

1.11 Modules

TypeScript also supports ECMAScript 2015 modules, which are files that contain top-level export and import directives. For this type of module the TypeScript compiler can emit both ECMAScript 2015 compliant code and down-level ECMAScript 3 or 5 compliant code for a variety of module loading systems, including CommonJS, Asynchronous Module Definition (AMD), and Universal Module Definition (UMD).


2 Basic Concepts

本文档的其余部分是TypeScript编程语言的正式规范,旨在作为 ECMAScript 2015语言规范 (特别是ECMA-262标准,第6版) 的附件来阅读 . 本文档描述了TypeScript所添加的语法语法,以及TypeScript编译器执行的编译时处理和类型检查,但是由于ECMAScript规范涵盖了该内容,因此仅极少讨论了程序的运行时行为.

2.1 Grammar Conventions

The syntactic grammar added by TypeScript language is specified throughout this document using the existing conventions and production names of the ECMAScript grammar. In places where TypeScript augments an existing grammar production it is so noted. For example:

  Declaration: ( Modified )
   …
   InterfaceDeclaration
   TypeAliasDeclaration
   EnumDeclaration

The '( Modified )' annotation indicates that an existing grammar production is being replaced, and the '…' references the contents of the original grammar production.

Similar to the ECMAScript grammar, if the phrase "[no LineTerminator here]" appears in the right-hand side of a production of the syntactic grammar, it indicates that the production is not a match if a LineTerminator occurs in the input stream at the indicated position.

2.2 Names

A core purpose of the TypeScript compiler is to track the named entities in a program and validate that they are used according to their designated meaning. Names in TypeScript can be written in several ways, depending on context. Specifically, a name can be written as

最常见的是,名称的编写要符合标识符的产生,即不是保留字的任何IdentifierName .

2.2.1 Reserved Words

The following keywords are reserved and cannot be used as an Identifier:

break             case              catch             class  
const             continue          debugger          default  
delete            do                else              enum  
export            extends           false             finally  
for               function          if                import  
in                instanceof        new               null  
return            super             switch            this  
throw             true              try               typeof  
var               void              while             with

The following keywords cannot be used as identifiers in strict mode code, but are otherwise not restricted:

implements        interface         let               package  
private           protected         public            static  
yield

The following keywords cannot be used as user defined type names, but are otherwise not restricted:

any               boolean           number            string  
symbol

The following keywords have special meaning in certain contexts, but are valid identifiers:

abstract          as                async             await  
constructor       declare           from              get  
is                module            namespace         of  
require           set               type

2.2.2 Property Names

The PropertyName production from the ECMAScript grammar is reproduced below:

  PropertyName:
   LiteralPropertyName
   ComputedPropertyName

  LiteralPropertyName:
   IdentifierName
   StringLiteral
   NumericLiteral

  ComputedPropertyName:
   [AssignmentExpression]

A property name can be any identifier (including a reserved word), a string literal, a numeric literal, or a computed property name. String literals may be used to give properties names that are not valid identifiers, such as names containing blanks. Numeric literal property names are equivalent to string literal property names with the string representation of the numeric literal, as defined in the ECMAScript specification.

2.2.3 Computed Property Names

ECMAScript 2015 permits object literals and classes to declare members with computed property names. A computed property name specifies an expression that computes the actual property name at run-time. Because the final property name isn't known at compile-time, TypeScript can only perform limited checks for entities declared with computed property names. However, a subset of computed property names known as well-known symbols can be used anywhere a PropertyName is expected, including property names within types. A computed property name is a well-known symbol if it is of the form

[ Symbol . xxx ]

In a well-known symbol, the identifier to the right of the dot must denote a property of the primitive type symbol in the type of the global variable 'Symbol', or otherwise an error occurs.

在指定ComputePropertyNamePropertyName中 ,除非属性名称出现在对象文字的属性分配( 4.5 )或非环境类的属性成员声明( 8.4 )中, 否则需要计算出的属性名称来表示众所周知的符号 ).

下面是一个接口的示例,该接口使用众所周知的符号名称声明属性:

interface Iterable<T> {  
    [Symbol.iterator](): Iterator<T>;  
}

TODO:更新以反映对带文字表达式计算属性名称的处理.

2.3 Declarations

Declarations introduce names in their associated declaration spaces. A name must be unique in its declaration space and can denote a value, a type, or a namespace, or some combination thereof. Effectively, a single name can have as many as three distinct meanings. For example:

var X: string;    // Value named X

type X = number;  // Type named X

namespace X {     // Namespace named X  
    type Y = string;  
}

表示值的名称具有关联的类型(第 3 ),并且可以在表达式中引用(第4.3节). 表示类型的名称可以单独在类型引用中使用,也可以在类型引用中点的右侧使用( 3.8.2 ). 表示名称空间的名称可以在类型引用中点的左侧使用.

When a name with multiple meanings is referenced, the context in which the reference occurs determines the meaning. For example:

var n: X;        // X references type  
var s: X.Y = X;  // First X references namespace, second X references value

在第一行中,X引用类型X,因为它出现在类型位置. 在第二行中,第一个X引用名称空间X,因为它出现在类型名称中的点之前,而第二个X引用变量X,因为它出现在表达式中.

声明为其声明的名称引入以下含义:

  • 变量,参数,函数,生成器,成员变量,成员函数,成员访问器或枚举成员声明引入了值的含义.
  • 接口,类型别名或类型参数声明引入了类型含义.
  • 类声明引入了值含义(构造函数)和类型含义(类类型).
  • 枚举声明引入了值的含义(枚举实例)和类型的含义(枚举类型).
  • 名称空间声明引入了名称空间含义(类型和名称空间容器),并且如果实例化了名称空间( 10.1节),则引入了值含义(名称空间实例).
  • 导入或导出声明引入了导入或导出实体的含义.

以下是一些声明示例,它们为名称引入了多种含义:

class C {      // Value and type named C  
    x: string;  
}

namespace N {  // Value and namespace named N  
    export var x: string;  
}

声明空间的存在如下:

  • 全局名称空间,每个模块和每个声明的名称空间均为其所包含的实体(无论是本地实体还是导出实体)具有声明空间.
  • 每个模块为其导出的实体都有一个声明空间. 模块中的所有导出声明都将占该声明空间.
  • 每个声明的名称空间都有一个用于其导出实体的声明空间. 命名空间中的所有导出声明都对此声明空间有所贡献. 已声明的名称空间的声明空间与具有相同的根容器和从该根容器开始具有相同的合格名称的其他已声明的名称空间共享.
  • 每个类声明都有一个用于实例成员和类型参数的声明空间,以及一个用于静态成员的声明空间.
  • 每个接口声明都有一个用于成员和类型参数的声明空间. 接口的声明空间与其他具有相同根容器和从该根容器开始具有相同限定名称的接口共享.
  • 每个枚举声明都有一个用于其枚举成员的声明空间. 一个枚举的声明空间与其他具有相同根容器且从该根容器开始具有相同限定名称的枚举共享.
  • 每个类型别名声明都有一个用于其类型参数的声明空间.
  • 每个类似函数的声明(包括函数声明,构造函数声明,成员函数声明,成员访问器声明,函数表达式和箭头函数)都有一个用于局部变量和类型参数的声明空间. 该声明空间包括参数声明,所有局部var和函数声明以及局部let,const,类,接口,类型别名和枚举声明,这些声明立即出现在函数体内,并且不再嵌套在块中.
  • 每个语句块都有一个声明空间,用于在该块中立即发生的本地let,const,类,接口,类型别名和枚举声明.
  • 每个对象文字都有其属性的声明空间.
  • 每个对象类型文字都有其成员的声明空间.

没有顶级导入或导出声明的源文件中的顶级声明属于全局命名空间 . 具有一个或多个顶级导入或导出声明的源文件中的顶级声明属于该源文件表示的模块 .

实体的容器定义如下:

  • 在名称空间声明中声明的实体的容器就是该名称空间声明.
  • 在模块中声明的实体的容器就是该模块.
  • 在全局名称空间中声明的实体的容器是全局名称空间.
  • 模块的容器是全局名称空间.

实体的根容器定义如下:

  • 非导出实体的根容器是该实体的容器.
  • 导出实体的根容器是实体容器的根容器.

直观地,实体的根容器是可从中访问实体的最外部模块或名称空间主体.

接口,枚举和名称空间是"开放式"的,这意味着相对于公共根具有相同限定名称的接口,枚举和名称空间声明会自动合并. 有关详细信息,请参见部分7.29.310.5 .

类中的实例成员和静态成员位于单独的声明空间中. 因此,以下内容是允许的:

class C {  
    x: number;          // Instance member  
    static x: string;   // Static member  
}

2.4 Scopes

The scope of a name is the region of program text within which it is possible to refer to the entity declared by that name without qualification of the name. The scope of a name depends on the context in which the name is declared. The contexts are listed below in order from outermost to innermost:

  • The scope of a name declared in the global namespace is the entire program text.
  • The scope of a name declared in a module is the source file of that module.
  • The scope of an exported name declared within a namespace declaration is the body of that namespace declaration and every namespace declaration with the same root and the same qualified name relative to that root.
  • The scope of a non-exported name declared within a namespace declaration is the body of that namespace declaration.
  • The scope of a type parameter name declared in a class or interface declaration is that entire declaration, including constraints, extends clause, implements clause, and declaration body, but not including static member declarations.
  • The scope of a type parameter name declared in a type alias declaration is that entire type alias declaration.
  • The scope of a member name declared in an enum declaration is the body of that declaration and every enum declaration with the same root and the same qualified name relative to that root.
  • The scope of a type parameter name declared in a call or construct signature is that entire signature declaration, including constraints, parameter list, and return type. If the signature is part of a function implementation, the scope includes the function body.
  • The scope of a parameter name declared in a call or construct signature is the remainder of the signature declaration. If the signature is part of a function-like declaration with a body (including a function declaration, constructor declaration, member function declaration, member accessor declaration, function expression, or arrow function), the scope includes the body of that function-like declaration.
  • The scope of a local var or function name declared anywhere in the body of a function-like declaration is the body of that function-like declaration.
  • The scope of a local let, const, class, interface, type alias, or enum declaration declared immediately within the body of a function-like declaration is the body of that function-like declaration.
  • The scope of a local let, const, class, interface, type alias, or enum declaration declared immediately within a statement block is the body of that statement block.

Scopes may overlap, for example through nesting of namespaces and functions. When the scopes of two names overlap, the name with the innermost declaration takes precedence and access to the outer name is either not possible or only possible by qualification.

当标识符解析为PrimaryExpression (第 4.3 )时,仅考虑作用域中具有值含义的名称,而忽略其他名称.

将标识符解析为TypeName时 (第3.8.2节),仅考虑作用域中具有类型含义的名称,而忽略其他名称.

当标识符解析为NamespaceName (第3.8.2节)时,仅考虑作用域中具有名称空间含义的名称,而忽略其他名称.

TODO: Include specific rules for alias resolution.

请注意,类和接口成员永远不会直接在作用域中,只能通过将点('.')运算符应用于类或接口实例来访问它们. 这甚至包括构造函数或成员函数中当前实例的成员,可通过将点运算符应用于this来访问它们.

正如上述规则所暗示的,与在同一名称空间的其他名称空间声明中声明的导出实体相比,名称空间中本地声明的实体在范围上更近. 例如:

var x = 1;  
namespace M {  
    export var x = 2;  
    console.log(x);     // 2  
}  
namespace M {  
    console.log(x);     // 2  
}  
namespace M {  
    var x = 3;  
    console.log(x);     // 3  
}

3 Types

TypeScript adds optional static types to JavaScript. Types are used to place static constraints on program entities such as functions, variables, and properties so that compilers and development tools can offer better verification and assistance during software development. TypeScript's static compile-time type system closely models the dynamic run-time type system of JavaScript, allowing programmers to accurately express the type relationships that are expected to exist when their programs run and have those assumptions pre-validated by the TypeScript compiler. TypeScript's type analysis occurs entirely at compile-time and adds no run-time overhead to program execution.

All types in TypeScript are subtypes of a single top type called the Any type. The any keyword references this type. The Any type is the one type that can represent any JavaScript value with no constraints. All other types are categorized as primitive types, object types, union types, intersection types, or type parameters. These types introduce various static constraints on their values.

The primitive types are the Number, Boolean, String, Symbol, Void, Null, and Undefined types along with user defined enum types. The number, boolean, string, symbol, and void keywords reference the Number, Boolean, String, Symbol, and Void primitive types respectively. The Void type exists purely to indicate the absence of a value, such as in a function with no return value. It is not possible to explicitly reference the Null and Undefined types—only values of those types can be referenced, using the null and undefined literals.

The object types are all class, interface, array, tuple, function, and constructor types. Class and interface types are introduced through class and interface declarations and are referenced by the name given to them in their declarations. Class and interface types may be generic types which have one or more type parameters.

Union types represent values that have one of multiple types, and intersection types represent values that simultaneously have more than one type.

Declarations of classes, properties, functions, variables and other language entities associate types with those entities. The mechanism by which a type is formed and associated with a language entity depends on the particular kind of entity. For example, a namespace declaration associates the namespace with an anonymous type containing a set of properties corresponding to the exported variables and functions in the namespace, and a function declaration associates the function with an anonymous type containing a call signature corresponding to the parameters and return type of the function. Types can be associated with variables through explicit type annotations, such as

var x: number;

or through implicit type inference, as in

var x = 1;

which infers the type of 'x' to be the Number primitive type because that is the type of the value used to initialize 'x'.

3.1 The Any Type

The Any type is used to represent any JavaScript value. A value of the Any type supports the same operations as a value in JavaScript and minimal static type checking is performed for operations on Any values. Specifically, properties of any name can be accessed through an Any value and Any values can be called as functions or constructors with any argument list.

The any keyword references the Any type. In general, in places where a type is not explicitly provided and TypeScript cannot infer one, the Any type is assumed.

The Any type is a supertype of all types, and is assignable to and from all types.

Some examples:

var x: any;             // Explicitly typed  
var y;                  // Same as y: any  
var z: { a; b; };       // Same as z: { a: any; b: any; }

function f(x) {         // Same as f(x: any): void  
    console.log(x);  
}

3.2 Primitive Types

The primitive types are the Number, Boolean, String, Symbol, Void, Null, and Undefined types and all user defined enum types.

3.2.1 The Number Type

The Number primitive type corresponds to the similarly named JavaScript primitive type and represents double-precision 64-bit format IEEE 754 floating point values.

The number keyword references the Number primitive type and numeric literals may be used to write values of the Number primitive type.

为了确定类型关系(第 3.11 )和访问属性(第4.13节),Number原语类型充当对象类型,其属性与全局接口类型" Number"相同.

一些例子:

var x: number;          // Explicitly typed  
var y = 0;              // Same as y: number = 0  
var z = 123.456;        // Same as z: number = 123.456  
var s = z.toFixed(2);   // Property of Number interface

3.2.2 The Boolean Type

The Boolean primitive type corresponds to the similarly named JavaScript primitive type and represents logical values that are either true or false.

The boolean keyword references the Boolean primitive type and the true and false literals reference the two Boolean truth values.

为了确定类型关系(第 3.11 )和访问属性(第4.13节),布尔基元类型的行为与对象类型具有与全局接口类型"布尔"相同的属性.

一些例子:

var b: boolean;         // Explicitly typed  
var yes = true;         // Same as yes: boolean = true  
var no = false;         // Same as no: boolean = false

3.2.3 The String Type

The String primitive type corresponds to the similarly named JavaScript primitive type and represents sequences of characters stored as Unicode UTF-16 code units.

The string keyword references the String primitive type and string literals may be used to write values of the String primitive type.

为了确定类型关系(第 3.11 )和访问属性(第4.13节),String基本类型的行为与具有与全局接口类型'String'相同的属性的对象类型相同.

一些例子:

var s: string;          // Explicitly typed  
var empty = "";         // Same as empty: string = ""  
var abc = 'abc';        // Same as abc: string = "abc"  
var c = abc.charAt(2);  // Property of String interface

3.2.4 The Symbol Type

The Symbol primitive type corresponds to the similarly named JavaScript primitive type and represents unique tokens that may be used as keys for object properties.

symbol关键字引用Symbol基本类型. 使用具有许多方法和属性的全局对象" Symbol"可获得符号值,并且可以将其作为函数调用. 特别是,全局对象'Symbol'定义了许多众所周知的符号( 2.2.3 ),它们可以以类似于标识符的方式使用. 请注意,"符号"对象仅在ECMAScript 2015环境中可用.

为了确定类型关系(第3.11节)和访问属性(第4.13节),Symbol原语类型表现为具有与全局接口类型'Symbol'相同属性的对象类型.

一些例子:

var secretKey = Symbol();  
var obj = {};  
obj[secretKey] = "secret message";  // Use symbol as property key  
obj[Symbol.toStringTag] = "test";   // Use of well-known symbol

3.2.5 The Void Type

The Void type, referenced by the void keyword, represents the absence of a value and is used as the return type of functions with no return value.

The only possible values for the Void type are null and undefined. The Void type is a subtype of the Any type and a supertype of the Null and Undefined types, but otherwise Void is unrelated to all other types.

NOTE: We might consider disallowing declaring variables of type Void as they serve no useful purpose. However, because Void is permitted as a type argument to a generic type or function it is not feasible to disallow Void properties or parameters.

3.2.6 The Null Type

The Null type corresponds to the similarly named JavaScript primitive type and is the type of the null literal.

The null literal references the one and only value of the Null type. It is not possible to directly reference the Null type itself.

The Null type is a subtype of all types, except the Undefined type. This means that null is considered a valid value for all primitive types, object types, union types, intersection types, and type parameters, including even the Number and Boolean primitive types.

Some examples:

var n: number = null;   // Primitives can be null  
var x = null;           // Same as x: any = null  
var e: Null;            // Error, can't reference Null type

3.2.7 The Undefined Type

The Undefined type corresponds to the similarly named JavaScript primitive type and is the type of the undefined literal.

The undefined literal denotes the value given to all uninitialized variables and is the one and only value of the Undefined type. It is not possible to directly reference the Undefined type itself.

The undefined type is a subtype of all types. This means that undefined is considered a valid value for all primitive types, object types, union types, intersection types, and type parameters.

Some examples:

var n: number;          // Same as n: number = undefined  
var x = undefined;      // Same as x: any = undefined  
var e: Undefined;       // Error, can't reference Undefined type

3.2.8 Enum Types

枚举类型是Number原语类型的不同用户定义子类型. 枚举类型使用枚举声明(第 9.1 进行声明,并使用类型引用(第3.8.2节)进行引用.

枚举类型可分配给Number原语类型,反之亦然,但是不同的枚举类型不能相互分配.

3.2.9 String Literal Types

专用签名(第 3.9.2.4 )允许将字符串文字用作参数类型注释中的类型. 字符串文字类型仅在该上下文中被允许,在其他地方则不允许.

所有字符串文字类型都是String基本类型的子类型.

TODO:更新以反映对字符串文字类型的扩展支持.

3.3 Object Types

Object types are composed from properties, call signatures, construct signatures, and index signatures, collectively called members.

Class and interface type references, array types, tuple types, function types, and constructor types are all classified as object types. Multiple constructs in the TypeScript language create object types, including:

  • Object type literals (section 3.8.3).
  • 数组类型文字(第3.8.4节).
  • 元组类型文字(第3.8.5节).
  • 函数类型文字(第3.8.8节).
  • 构造函数类型文字(第3.8.9节).
  • 对象文字(第4.5节).
  • 数组文字(第4.6节).
  • 函数表达式(第4.10节)和函数声明( 6.1 ).
  • 由类声明创建的构造函数类型(见8.2.5节).
  • 由名称空间声明创建的名称空间实例类型(第10.3节).

3.3.1 Named Type References

对类和接口类型的类型引用(第 3.8.2 )被归类为对象类型. 泛型类和接口类型的类型引用包括类型参数,这些类型参数将替换类或接口的类型参数以产生实际的对象类型.

3.3.2 Array Types

数组类型表示具有常见元素类型的JavaScript数组. 数组类型是从全局名称空间中的通用接口类型" Array"创建的命名类型引用,其中数组元素类型为类型实参. 数组类型文字(第 3.8.4 )提供了创建此类引用的简写符号.

"数组"接口的声明包括属性"长度"和元素类型的数字索引签名,以及其他成员:

interface Array<T> {  
    length: number;  
    [x: number]: T;  
    // Other members  
}

数组文字(第4.6节)可用于创建数组类型的值. 例如

var a: string[] = ["hello", "world"];

如果类型可以分配给any[]类型(第3.11.4节 ),则称其为类似数组的类型 .

3.3.3 Tuple Types

元组类型表示具有单独跟踪的元素类型的JavaScript数组. 元组类型是使用元组类型文字(第 3.8.5 编写的 . 元组类型将一组数字命名的属性与数组类型的成员结合在一起. 具体来说,元组类型

[ T0, T1, ..., Tn ]

结合属性集

{  
    0: T0;  
    1: T1;  
    ...  
    n: Tn;  
}

数组类型的成员的元素类型是元组元素类型的联合类型(第3.4节).

数组文字(第4.6节)可用于创建元组类型的值. 例如:

var t: [number, string] = [3, "three"];  
var n = t[0];  // Type of n is number  
var s = t[1];  // Type of s is string  
var i: number;  
var x = t[i];  // Type of x is number | string

可以通过声明从Array <T>派生并引入数字命名属性的接口来创建命名元组类型. 例如:

interface KeyValuePair<K, V> extends Array<K | V> { 0: K; 1: V; }

var x: KeyValuePair<number, string> = [10, "ten"];

如果类型具有数字名称为" 0"的属性,则称其为类似元组的类型 .

3.3.4 Function Types

包含一个或多个调用签名的对象类型称为函数类型 . 可以使用函数类型文字(第 3.8.8 )或通过在对象类型文字中包含调用签名来编写函数类型 .

3.3.5 Constructor Types

包含一个或多个构造签名的对象类型被称为构造函数类型 . 构造函数类型可以使用构造函数类型文字(第 3.8.9 )或在对象类型文字中包含构造签名来编写 .

3.3.6 Members

Every object type is composed from zero or more of the following kinds of members:

  • Properties, which define the names and types of the properties of objects of the given type. Property names are unique within their type.
  • Call signatures, which define the possible parameter lists and return types associated with applying call operations to objects of the given type.
  • Construct signatures, which define the possible parameter lists and return types associated with applying the new operator to objects of the given type.
  • Index signatures, which define type constraints for properties in the given type. An object type can have at most one string index signature and one numeric index signature.

Properties are either public, private, or protected and are either required or optional:

通过包含带有字符串文字类型的参数,可以对调用和构造签名进行专门化 (第3.9.2.4节). 专用签名用于表示模式,其中某些参数的特定字符串值会导致其他参数的类型或函数结果变得更加特殊.

3.4 Union Types

Union types represent values that may have one of several distinct representations. A value of a union type A | B is a value that is either of type A or type B. Union types are written using union type literals (section 3.8.6).

联合类型包含一组有序的组成类型. 虽然通常是A | B等于B | A,构成类型的顺序可以在确定联合类型的呼叫,并构建签名时无关紧要.

Union types have the following subtype relationships:

  • 甲联合类型U是类型T的子类型,如果U中每种类型为T的子类型.
  • A型,T是联合U型的一个亚型如果T是任何类型的以U的子类型.

同样,联合类型具有以下可分配性关系:

  • 如果U中的每个类型都可以分配给T,则可以将联合类型U分配给类型T.
  • 如果T可分配给U中的任何类型,则类型T可分配给联合类型U.

|| 条件运算符(第4.19.74.20节)可能会产生联合类型的值,而数组文字(第4.6节)可能会产生以联合类型作为其元素类型的数组值.

Type guards (section 4.24) may be used to narrow a union type to a more specific type. In particular, type guards are useful for narrowing union type values to a non-union type values.

在这个例子中

var x: string | number;  
var test: boolean;  
x = "hello";            // Ok  
x = 42;                 // Ok  
x = test;               // Error, boolean not assignable  
x = test ? 5 : "five";  // Ok  
x = test ? 0 : false;   // Error, number | boolean not assignable

可以为'x'分配string类型, number或联合类型string | number string | number ,但没有其他任何类型. 要访问'x'中的值,可以使用类型保护将'x'的类型首先缩小为stringnumber

var n = typeof x === "string" ? x.length : x;  // Type of n is number

出于属性访问和函数调用的目的,联合类型的表观成员(第3.11.1节)是其每种构成类型中都存在的成员,而类型是构成类型中各个表观成员的联合. 以下示例说明了根据对象类型创建联合类型时发生的成员类型合并.

interface A {  
    a: string;  
    b: number;  
}

interface B {  
    a: number;  
    b: number;  
    c: number;  
}

var x: A | B;  
var a = x.a;  // a has type string | number  
var b = x.b;  // b has type number  
var c = x.c;  // Error, no property c in union type

请注意," xa"具有联合类型,因为" a"的类型在" A"和" B"中是不同的,而" xb"只是具有类型号,因为这在" A"和" b"中都是" b"的类型'B'. 还要注意,没有属性" xc",因为只有" B"具有属性" c".

当用作上下文类型(第4.23节)时,联合类型具有那些以其任何构成类型存在的成员,这些类型是构成类型中各个成员的联合. 具体来说,用作上下文类型的并集类型具有第3.11.1节中定义的明显成员,只是特定成员仅需要以一种或多种构成类型而不是所有构成类型存在即可.

3.5 Intersection Types

Intersection types represent values that simultaneously have multiple types. A value of an intersection type A & B is a value that is both of type A and type B. Intersection types are written using intersection type literals (section 3.8.7).

交集类型包含一组有序的组成类型. 虽然AB等效于BA通常是正确的, 但是在确定调用和构造交集类型的签名时,构成类型的顺序可能很重要.

交叉点类型具有以下子类型关系:

  • 的交点I型是类型T的子类型,如果任何类型的T的子类型.
  • A型,T是一个交叉点的I型的一个亚型,如果T是每类型的子类型.

同样,交叉点类型具有以下可分配性关系:

  • 的交点I型被分配给一个类型T,如果任何类型的I是可分配至T.
  • 如果T可分配给I中的每个类型,则类型T可分配给相交类型I.

出于属性访问和函数调用的目的,交集类型的表观成员(第3.11.1节)是存在于其一种或多种组成类型中的那些,其类型是组成类型中各个表观成员的交集. 以下示例说明了根据对象类型创建交集类型时发生的成员类型合并.

interface A { a: number }  
interface B { b: number }

var ab: A & B = { a: 1, b: 1 };  
var a: A = ab;  // A & B assignable to A  
var b: B = ab;  // A & B assignable to B

interface X { p: A }  
interface Y { p: B }

var xy: X & Y = { p: ab };  // X & Y has property p of type A & B

type F1 = (a: string, b: string) => void;  
type F2 = (a: number, b: number) => void;

var f: F1 & F2 = (a: string | number, b: string | number) => { };  
f("hello", "world");  // Ok  
f(1, 2);              // Ok  
f(1, "test");         // Error

联合和交集类型运算符可以应用于类型参数. 例如,此功能可用于对合并对象的函数进行建模:

function extend<T, U>(first: T, second: U): T & U {  
    // Extend first with properties of second  
}

var x = extend({ a: "hello" }, { b: 42 });  
var s = x.a;  
var n = x.b;

可以创建交集类型,对于这些交集类型,除null或undefined以外的其他值均不可能. 例如,基本类型(例如string & number交集属于此类别.

3.6 Type Parameters

A type parameter represents an actual type that the parameter is bound to in a generic type reference or a generic function call. Type parameters have constraints that establish upper bounds for their actual type arguments.

Since a type parameter represents a multitude of different type arguments, type parameters have certain restrictions compared to other types. In particular, a type parameter cannot be used as a base class or interface.

3.6.1 Type Parameter Lists

Class, interface, type alias, and function declarations may optionally include lists of type parameters enclosed in < and > brackets. Type parameters are also permitted in call signatures of object, function, and constructor type literals.

  TypeParameters:
   <TypeParameterList>

  TypeParameterList:
   TypeParameter
   TypeParameterList,TypeParameter

  TypeParameter:
   BindingIdentifierConstraintopt

  Constraint:
   extendsType

Type parameter names must be unique. A compile-time error occurs if two or more type parameters in the same TypeParameterList have the same name.

The scope of a type parameter extends over the entire declaration with which the type parameter list is associated, with the exception of static member declarations in classes.

A type parameter may have an associated type parameter constraint that establishes an upper bound for type arguments. Type parameters may be referenced in type parameter constraints within the same type parameter list, including even constraint declarations that occur to the left of the type parameter.

The base constraint of a type parameter T is defined as follows:

  • If T has no declared constraint, T's base constraint is the empty object type {}.
  • If T's declared constraint is a type parameter, T's base constraint is that of the type parameter.
  • Otherwise, T's base constraint is T's declared constraint.

In the example

interface G<T, U extends V, V extends Function> { }

the base constraint of 'T' is the empty object type and the base constraint of 'U' and 'V' is 'Function'.

为了确定类型关系(第 3.11 ),类型参数似乎是其基本约束的子类型. 同样,在属性访问(第4.13节), new操作(第4.14节)和函数调用(第4.15节)中,类型参数似乎具有其基本约束的成员,但没有其他成员.

类型参数直接或间接成为其自身的约束是错误的. 例如,以下两个声明均无效:

interface A<T extends T> { }

interface B<T extends U, U extends T> { }

3.6.2 Type Argument Lists

泛型类型的类型引用(第 3.8.2 )必须包括用尖括号括起来并用逗号分隔的类型参数列表. 类似地,对泛型函数的调用(第4.15节)可以显式包括类型实参列表,而不是依赖于类型推断.

  TypeArguments:
   <TypeArgumentList>

  TypeArgumentList:
   TypeArgument
   TypeArgumentList,TypeArgument

  TypeArgument:
   Type

类型参数与所引用的泛型类型或函数的类型参数一一对应. 需要一个类型实参列表为每个对应的类型形参精确指定一个类型实参,并且需要一个约束类型形参的每个类型实参来满足该类型形参的约束. 如果在将类型实参替换为类型实参后将类型实参分配给约束类型(第3.11.4节 ),则类型实参满足类型参数约束.

给出声明

interface G<T, U extends Function> { }

a type reference of the form 'G<A, B>' places no requirements on 'A' but requires 'B' to be assignable to 'Function'.

将类型实参替换为通用类型或通用签名中的类型参数的过程称为实例化通用类型或签名. 如果提供的类型参数不满足其对应类型参数的约束,则泛型类型或签名的实例化可能会失败.

3.6.3 This-types

每个类和接口都有一个this类型 ,它表示类或接口的声明中类或接口实例的实际类型. 在类型位置使用关键字this引用this-type. 在类的实例方法和构造函数中,表达式this的类型(第 4.2 )是类的this-type.

类和接口支持继承,因此在方法中this方法表示的实例不一定是包含类的实例-实际上,它可能是派生类或接口的实例. 为了对此关系建模,将类或接口的此类型分类为类型参数. 与其他类型参数不同,不可能为this-type显式传递类型参数. 相反,在对类或接口类型的类型引用中,类型引用本身会作为this-type的类型参数隐式传递. 例如:

class A {  
    foo() {  
        return this;  
    }  
}

class B extends A {  
    bar() {  
        return this;  
    }  
}

let b: B;  
let x = b.foo().bar();  // Fluent pattern works, type of x is B

在上面的b声明中,类型引用B本身作为B的this-type的类型参数传递. 因此,引用的类型是类的实例化B其中类型的所有出现this与取代B ,并且由于该原因的foo的方法B实际上返回B (相对于A ).

给定类或接口类型C的this-type隐含一个约束,该约束包括对C的类型引用,其中C自己的类型参数作为类型实参传递,并且该类型引用作为this-type的类型实参传递.

3.7 Named Types

类,接口,枚举和类型别名是通过类声明(第 8.1 ),接口声明(第7.1节),枚举声明( 9.1 )和类型别名声明(第3.10 引入的命名类型 . 类,接口和类型别名可以具有类型参数,然后称为泛型类型 . 相反,没有类型参数的命名类型称为非泛型类型 .

接口声明仅引入命名类型,而类声明引入命名类型构造函数,这些函数创建这些命名类型的实现实例. 由类和接口声明引入的命名类型只有细微的差别(类不能声明可选成员,接口不能声明私有或受保护的成员),并且在大多数情况下可以互换. 特别是,仅具有公共成员的类声明引入的命名类型的功能与接口声明创建的命名类型完全相同.

命名类型通过类型引用 (第3.8.2节)进行引用,这些引用指定类型名称,并在适用时指定要替换命名类型的类型参数的类型实参.

从技术上讲,命名类型不是类型-仅引用命名类型. 这种区别在泛型类型中尤为明显:泛型类型是"模板",可以通过编写类型引用来从其创建多个实际类型,这些类型引用提供类型参数来代替泛型类型的类型参数. 此替换过程称为实例化泛型类型. 只有实例化泛型类型后,它才表示实际类型.

TypeScript具有结构类型系统,因此,通用类型的实例与等效的手动编写的扩展没有区别. 例如,给定声明

interface Pair<T1, T2> { first: T1; second: T2; }

类型参考

Pair<string, Entity>

与类型没有区别

{ first: string; second: Entity; }

3.8 Specifying Types

Types are specified either by referencing their keyword or name, or by writing object type literals, array type literals, tuple type literals, function type literals, constructor type literals, or type queries.

  Type:
   UnionOrIntersectionOrPrimaryType
   FunctionType
   ConstructorType

  UnionOrIntersectionOrPrimaryType:
   UnionType
   IntersectionOrPrimaryType

  IntersectionOrPrimaryType:
   IntersectionType
   PrimaryType

  PrimaryType:
   ParenthesizedType
   PredefinedType
   TypeReference
   ObjectType
   ArrayType
   TupleType
   TypeQuery
   ThisType

  ParenthesizedType:
   (Type)

Parentheses are required around union, intersection, function, or constructor types when they are used as array element types; around union, function, or constructor types in intersection types; and around function or constructor types in union types. For example:

(string | number)[]  
((x: string) => string) | ((x: number) => number)  
(A | B) & (C | D)

The different forms of type notations are described in the following sections.

3.8.1 Predefined Types

The any, number, boolean, string, symbol and void keywords reference the Any type and the Number, Boolean, String, Symbol, and Void primitive types respectively.

  PredefinedType:
   any
   number
   boolean
   string
   symbol
   void

The predefined type keywords are reserved and cannot be used as names of user defined types.

3.8.2 Type References

A type reference references a named type or type parameter through its name and, in the case of a generic type, supplies a type argument list.

  TypeReference:
   TypeName[no LineTerminator here]TypeArgumentsopt

  TypeName:
   IdentifierReference
   NamespaceName.IdentifierReference

  NamespaceName:
   IdentifierReference
   NamespaceName.IdentifierReference

A TypeReference consists of a TypeName that a references a named type or type parameter. A reference to a generic type must be followed by a list of TypeArguments (section 3.6.2).

TypeName是单个标识符或由点分隔的标识符序列. 在类型名称中,除最后一个标识符外,所有标识符均指名称空间,最后一个标识符指代命名类型.

在第2.4节中描述了由单个标识符组成的TypeName的解析.

首先解析名称空间名称N ,以解析NX形式的TypeName ,其中NNamespaceNameXIdentifierReference . 如果N的解析成功,并且结果命名空间的导出成员集(第10.411.3.4.4节)包含命名类型X ,则NX引用该成员. 否则, NX是不确定的.

由单个标识符组成的NamespaceName的解析在2.4节中描述. 在命名空间声明(部分声明标识符10.1 )或进口声明(部分10.311.3.211.3.3 )可以被分类为名称空间.

首先解析名称空间名称N ,以解析NX形式的名称空间名称 ,其中NNamespaceNameXIdentifierReference . 如果N的解析成功,并且结果命名空间的导出成员集(第10.411.3.4.4节)包含导出的命名空间成员X ,则NX引用该成员. 否则, NX是不确定的.

需要使用对通用类型的类型引用来为所引用的通用类型的每个类型参数精确指定一个类型参数,并且每个类型参数都必须可分配给(第3.11.4节 )相应类型参数的约束,否则将产生错误发生. 一个例子:

interface A { a: string; }

interface B extends A { b: string; }

interface C extends B { c: string; }

interface G<T, U extends B> {  
    x: T;  
    y: U;  
}

var v1: G<A, C>;               // Ok  
var v2: G<{ a: string }, C>;   // Ok, equivalent to G<A, C>  
var v3: G<A, A>;               // Error, A not valid argument for U  
var v4: G<G<A, B>, C>;         // Ok  
var v5: G<any, any>;           // Ok  
var v6: G<any>;                // Error, wrong number of arguments  
var v7: G;                     // Error, no arguments

类型实参只是一个类型 ,它本身可以是对通用类型的类型引用,如上例中的" v4"所示.

如第3.7节所述,对通用类型G的类型引用指定一种类型,其中G的所有类型参数的出现都已用类型引用中提供的实际类型自变量替换. 例如,上面的'v1'声明等同于:

var v1: {  
    x: { a: string; }  
    y: { a: string; b: string; c: string };  
};

3.8.3 Object Type Literals

An object type literal defines an object type by specifying the set of members that are statically considered to be present in instances of the type. Object type literals can be given names using interface declarations but are otherwise anonymous.

  ObjectType:
   {TypeBodyopt}

  TypeBody:
   TypeMemberList;opt
   TypeMemberList,opt

  TypeMemberList:
   TypeMember
   TypeMemberList;TypeMember
   TypeMemberList,TypeMember

  TypeMember:
   PropertySignature
   CallSignature
   ConstructSignature
   IndexSignature
   MethodSignature

The members of an object type literal are specified as a combination of property, call, construct, index, and method signatures. Object type members are described in section 3.9.

3.8.4 Array Type Literals

An array type literal is written as an element type followed by an open and close square bracket.

  ArrayType:
   PrimaryType[no LineTerminator here][]

数组类型文字会引用具有给定元素类型的数组类型(第 3.3.2 ). 数组类型文字是在全局命名空间中引用通用接口类型" Array"的简写形式,其中元素类型作为类型实参.

当联合,交集,函数或构造函数类型用作数组元素类型时,必须将其括在括号中. 例如:

(string | number)[]  
(() => string)[]

或者,可以使用" Array <T>"符号来编写数组类型. 例如,以上类型等同于

Array<string | number>  
Array<() => string>

3.8.5 Tuple Type Literals

A tuple type literal is written as a sequence of element types, separated by commas and enclosed in square brackets.

  TupleType:
   [TupleElementTypes]

  TupleElementTypes:
   TupleElementType
   TupleElementTypes,TupleElementType

  TupleElementType:
   Type

A tuple type literal references a tuple type (section 3.3.3).

3.8.6 Union Type Literals

A union type literal is written as a sequence of types separated by vertical bars.

  UnionType:
   UnionOrIntersectionOrPrimaryType|IntersectionOrPrimaryType

A union type literal references a union type (section 3.4).

3.8.7 Intersection Type Literals

An intersection type literal is written as a sequence of types separated by ampersands.

  IntersectionType:
   IntersectionOrPrimaryType&PrimaryType

An intersection type literal references an intersection type (section 3.5).

3.8.8 Function Type Literals

A function type literal specifies the type parameters, regular parameters, and return type of a call signature.

  FunctionType:
   TypeParametersopt(ParameterListopt)=>Type

A function type literal is shorthand for an object type containing a single call signature. Specifically, a function type literal of the form

< T1, T2, ... > ( p1, p2, ... ) => R

is exactly equivalent to the object type literal

{ < T1, T2, ... > ( p1, p2, ... ) : R }

Note that function types with multiple call or construct signatures cannot be written as function type literals but must instead be written as object type literals.

3.8.9 Constructor Type Literals

A constructor type literal specifies the type parameters, regular parameters, and return type of a construct signature.

  ConstructorType:
   newTypeParametersopt(ParameterListopt)=>Type

A constructor type literal is shorthand for an object type containing a single construct signature. Specifically, a constructor type literal of the form

new < T1, T2, ... > ( p1, p2, ... ) => R

is exactly equivalent to the object type literal

{ new < T1, T2, ... > ( p1, p2, ... ) : R }

Note that constructor types with multiple construct signatures cannot be written as constructor type literals but must instead be written as object type literals.

3.8.10 Type Queries

A type query obtains the type of an expression.

  TypeQuery:
   typeofTypeQueryExpression

  TypeQueryExpression:
   IdentifierReference
   TypeQueryExpression.IdentifierName

类型查询由关键字typeof及其后的表达式组成. 该表达式仅限于单个标识符或由句点分隔的标识符序列. 将该表达式作为标识符表达式(第 4.3 )或属性访问表达式(第4.13节)进行处理,其扩展类型(第3.12节)成为结果. 与其他静态类型构造类似,类型查询将从生成的JavaScript代码中删除,并且不增加运行时开销.

类型查询对于捕获由各种构造(例如对象文字,函数声明和名称空间声明)生成的匿名类型很有用. 例如:

var a = { x: 10, y: 20 };  
var b: typeof a;

上面的'b'与'a'具有相同的类型,即{ x: number; y: number; } { x: number; y: number; } { x: number; y: number; } .

如果声明包含类型注释,该注释通过类型查询的循环路径或包含类型查询的类型引用引用要声明的实体,则结果类型为Any类型. 例如,以下所有变量的类型都为"任意":

var c: typeof c;  
var d: typeof e;  
var e: typeof d;  
var f: Array<typeof f>;

但是,如果类型查询的循环路径包括至少一个ObjectTypeFunctionTypeConstructorType ,则构造表示递归类型:

var g: { x: typeof g; };  
var h: () => typeof h;

在这里," g"和" gx"具有相同的递归类型,同样," h"和" h()"具有相同的递归类型.

3.8.11 This-Type References

this关键字用于引用类或接口的this-type(第 3.6.3 ).

  ThisType:
   this

一个ThisType的含义取决于最靠近封闭FunctionDeclaration,FunctionExpression,PropertyDefinition,ClassElement,TypeMember,被称为ThisType的根声明,如下所示:

  • 当根声明是类的实例成员或构造函数时, ThisType引用该类的this-type.
  • 当根声明是接口类型的成员时, ThisType引用该接口的此类型.
  • 否则, ThisType是错误.

请注意,为避免歧义,不可能在嵌套对象类型文字中引用此类的此类或接口. 在这个例子中

interface ListItem {  
    getHead(): this;  
    getTail(): this;  
    getHeadAndTail(): { head: this, tail: this };  // Error  
}

the this references on the last line are in error because their root declarations are not members of a class or interface. The recommended way to reference the this-type of an outer class or interface in an object type literal is to declare an intermediate generic type and pass this as a type argument. For example:

type HeadAndTail<T> = { head: T, tail: T };

interface ListItem {  
    getHead(): this;  
    getTail(): this;  
    getHeadAndTail(): HeadAndTail<this>;  
}

3.9 Specifying Members

对象类型文字(第 3.8.3 )的成员被指定为属性,调用,构造,索引和方法签名的组合.

3.9.1 Property Signatures

A property signature declares the name and type of a property member.

  PropertySignature:
   PropertyName?optTypeAnnotationopt

  TypeAnnotation:
   :Type

属性签名PropertyName 2.2.2 )在其包含类型内必须是唯一的,并且如果它是计算所得的属性名称( 2.2.3 ),则必须表示一个众所周知的符号. 如果属性名称后面带有问号,则该属性为可选. 否则,该属性是必需的.

如果属性签名省略TypeAnnotation ,则假定为Any类型.

3.9.2 Call Signatures

呼叫签名定义了类型参数,参数列表和返回类型,与将呼叫操作(第 4.15 )应用于包含类型的实例相关联 . 通过定义多个不同的呼叫签名,一种类型可能会使呼叫操作超载 .

  CallSignature:
   TypeParametersopt(ParameterListopt)TypeAnnotationopt

A call signature that includes TypeParameters (section 3.6.1) is called a 通用呼叫签名. Conversely, a call signature with no TypeParameters is called a non-generic call signature.

调用签名不仅是对象类型文字的成员,还出现在方法签名(第3.9.5节),函数表达式(第4.10节)和函数声明(第6.1节)中.

包含调用签名的对象类型被称为函数类型 .

3.9.2.1 Type Parameters

调用签名中的类型参数(第 3.6.1 )提供了一种在调用操作中表达参数与返回类型之间关系的机制. 例如,签名可能会引入类型参数,并将其用作参数类型和返回类型,实际上是描述一个函数,该函数返回与其参数相同类型的值.

类型参数可以在引入它们的呼叫签名的参数类型和返回类型注释中引用,但不能在类型参数约束中引用.

用于呼叫签名类型参数的类型参数(第3.6.2节)可以在调用操作中明确指定,或者在可能的情况下,可以从调用中的常规参数的类型推断出类型参数(第4.15.2节). 特定类型参数集的通用调用签名的实例化是通过将每个类型参数替换为其对应的类型参数而形成的调用签名.

下面是带有类型参数的呼叫签名的一些示例.

一个函数,它接受任何类型的参数,并返回相同类型的值:

<T>(x: T): T

该函数接受两个相同类型的值,并返回该类型的数组:

<T>(x: T, y: T): T[]

A function taking two arguments of different types, returning an object with properties 'x' and 'y' of those types:

<T, U>(x: T, y: U): { x: T; y: U; }

一个函数采用一种类型的数组和一个函数参数,然后返回另一种类型的数组,其中该函数参数采用第一个数组元素类型的值并返回第二个数组元素类型的值:

<T, U>(a: T[], f: (x: T) => U): U[]

3.9.2.2 Parameter List

A signature's parameter list consists of zero or more required parameters, followed by zero or more optional parameters, finally followed by an optional rest parameter.

  ParameterList:
   RequiredParameterList
   OptionalParameterList
   RestParameter
   RequiredParameterList,OptionalParameterList
   RequiredParameterList,RestParameter
   OptionalParameterList,RestParameter
   RequiredParameterList,OptionalParameterList,RestParameter

  RequiredParameterList:
   RequiredParameter
   RequiredParameterList,RequiredParameter

  RequiredParameter:
   AccessibilityModifieroptBindingIdentifierOrPatternTypeAnnotationopt
   BindingIdentifier:StringLiteral

  AccessibilityModifier:
   public
   private
   protected

  BindingIdentifierOrPattern:
   BindingIdentifier
   BindingPattern

  OptionalParameterList:
   OptionalParameter
   OptionalParameterList,OptionalParameter

  OptionalParameter:
   AccessibilityModifieroptBindingIdentifierOrPattern?TypeAnnotationopt
   AccessibilityModifieroptBindingIdentifierOrPatternTypeAnnotationoptInitializer
   BindingIdentifier?:StringLiteral

  RestParameter:
   ...BindingIdentifierTypeAnnotationopt

参数声明可以指定标识符或绑定模式( 5.2.2 ). 参数声明中指定的标识符和参数列表中的绑定模式在该参数列表中必须是唯一的.

签名中参数的类型确定如下:

  • 如果声明中包含类型注释,则参数为该类型.
  • 否则,如果声明包含初始化程序表达式(仅当参数列表与函数体一起出现时才允许使用),则参数类型为初始化程序表达式类型的扩展形式(第3.12节).
  • 否则,如果声明指定了绑定模式,则参数类型是该绑定模式的隐含类型(第5.2.3节).
  • 否则,如果参数是rest参数,则参数类型为any[] .
  • 否则,参数类型为any .

仅当参数出现在ConstructorImplementation的参数列表中(第8.3.1节)且未指定BindingPattern时,才允许其包含publicprivateprotected修饰符.

rest参数的类型注释必须表示数组类型.

当参数类型注释指定字符串文字类型时,包含的签名是专用签名(第3.9.2.4节). 不允许将专用签名与函数体结合使用,即FunctionExpressionFunctionImplementationMemberFunctionImplementationConstructorImplementation语法生成不允许使用字符串文字类型的参数.

可以通过在参数的名称或绑定模式后加上问号( ? )或包括初始化程序来将参数标记为可选. 仅当参数列表与函数体一起出现时才允许使用初始化器(包括绑定属性或元素初始化器),即仅在FunctionExpressionFunctionImplementationMemberFunctionImplementationConstructorImplementation语法生成中.

TODO:更新以反映绑定参数在实现签名中不能为可选.

待办事项:更新以反映支持初始化程序所需的参数.

3.9.2.3 Return Type

If present, a call signature's return type annotation specifies the type of the value computed and returned by a call operation. A void return type annotation is used to indicate that a function has no return value.

When a call signature with no return type annotation occurs in a context without a function body, the return type is assumed to be the Any type.

When a call signature with no return type annotation occurs in a context that has a function body (specifically, a function implementation, a member function implementation, or a member accessor declaration), the return type is inferred from the function body as described in section 6.3.

3.9.2.4 Specialized Signatures

当参数类型注释指定字符串文字类型(第 3.2.9 )时,包含的签名被视为专用签名. 专用签名用于表示模式,其中某些参数的特定字符串值会导致其他参数的类型或函数结果变得更加特殊. 例如,声明

interface Document {  
    createElement(tagName: "div"): HTMLDivElement;   
    createElement(tagName: "span"): HTMLSpanElement;  
    createElement(tagName: "canvas"): HTMLCanvasElement;  
    createElement(tagName: string): HTMLElement;  
}

声明使用字符串文字" div"," span"和" canvas"调用" createElement"分别返回类型为" HTMLDivElement"," HTMLSpanElement"和" HTMLCanvasElement"的值,并使用所有其他字符串表达式返回" HTMLElement"类型的值.

编写上面的声明之类的重载声明时,最后列出非专用签名非常重要. 这是因为重载解析(第4.15.1节)按声明顺序处理候选者,并选择匹配的第一个候选者.

中的对象类型的每个专门的呼叫或构建签名必须分配给至少一个非专业相同的对象类型(其中,如果仅含有A的对象类型的呼叫签名A被认为是分配给另一个呼叫签名呼叫或构建体签名可以分配给仅包含B的对象类型. 例如,上面示例中的'createElement'属性的类型包含三个专用签名,所有这些签名都可以分配给该类型中的非专用签名.

3.9.3 Construct Signatures

构造签名定义了与将new运算符(第 4.14 )应用于包含类型的实例相关联的参数列表和返回类型. 通过使用不同的参数列表定义多个构造签名,类型可以使new操作过载.

  ConstructSignature:
   newTypeParametersopt(ParameterListopt)TypeAnnotationopt

构造签名的类型参数,参数列表和返回类型应遵循与调用签名相同的规则.

包含构造签名的类型被称为构造函数类型 .

3.9.4 Index Signatures

An index signature defines a type constraint for properties in the containing type.

  IndexSignature:
   [BindingIdentifier:string]TypeAnnotation
   [BindingIdentifier:number]TypeAnnotation

There are two kinds of index signatures:

  • String index signatures, specified using index type string, define type constraints for all properties and numeric index signatures in the containing type. Specifically, in a type with a string index signature of type T, all properties and numeric index signatures must have types that are assignable to T.
  • Numeric index signatures, specified using index type number, define type constraints for all numerically named properties in the containing type. Specifically, in a type with a numeric index signature of type T, all numerically named properties must have types that are assignable to T.

A numerically named property is a property whose name is a valid numeric literal. Specifically, a property with a name N for which ToString(ToNumber(N)) is identical to N, where ToString and ToNumber are the abstract operations defined in ECMAScript specification.

An object type can contain at most one string index signature and one numeric index signature.

Index signatures affect the determination of the type that results from applying a bracket notation property access to an instance of the containing type, as described in section 4.13.

3.9.5 Method Signatures

A method signature is shorthand for declaring a property of a function type.

  MethodSignature:
   PropertyName?optCallSignature

如果PropertyName是计算的属性名称( 2.2.3 ),则它必须指定一个众所周知的符号. 如果PropertyName后面带有问号,则该属性为可选. 否则,该属性是必需的. 仅对象类型文字和接口可以声明可选属性.

表单的方法签名

f < T1, T2, ... > ( p1, p2, ... ) : R

等同于属性声明

f : { < T1, T2, ... > ( p1, p2, ... ) : R }

文字类型可以通过声明多个具有相同名称但参数列表不同的方法签名来重载方法. 必须全部重载(省略问号),或者全部重载是可选的(包括问号). 一组重载的方法签名对应于单个属性的声明,该声明的类型由等效的一组调用签名组成. 特别

f < T1, T2, ... > ( p1, p2, ... ) : R ;  
f < U1, U2, ... > ( q1, q2, ... ) : S ;  
...

相当于

f : {  
    < T1, T2, ... > ( p1, p2, ... ) : R ;  
    < U1, U2, ... > ( q1, q2, ... ) : S ;  
    ...  
} ;

在下面的对象类型示例中

{  
    func1(x: number): number;         // Method signature  
    func2: (x: number) => number;     // Function type literal  
    func3: { (x: number): number };   // Object type literal  
}

属性" func1"," func2"和" func3"都是相同的类型,即具有单个调用签名并带有数字并返回数字的对象类型. 同样,在对象类型中

{  
    func4(x: number): number;  
    func4(s: string): string;  
    func5: {  
        (x: number): number;  
        (s: string): string;  
    };  
}

属性" func4"和" func5"具有相同的类型,即具有两个调用签名的对象类型,分别带有并返回数字和字符串.

3.10 Type Aliases

A type alias declaration introduces a type alias in the containing declaration space.

  TypeAliasDeclaration:
   typeBindingIdentifierTypeParametersopt=Type;

A type alias serves as an alias for the type specified in the type alias declaration. Unlike an interface declaration, which always introduces a named object type, a type alias declaration can introduce a name for any kind of type, including primitive, union, and intersection types.

类型别名可以选择具有类型参数(第 3.6.1 ), 这些类型参数用作在类型引用中引用类型别名时要提供的实际类型的占位符. 具有类型参数的类型别名称为通用类型别名 . 通用类型别名声明的类型参数在范围内,并且可以在别名Type中引用.

使用类型引用( 3.8.2 )引用类型别名. 对通用类型别名的类型引用使用给定的类型参数生成别名类型的实例化. 编写对非通用类型别名的引用与编写别名类型本身具有完全相同的效果,而编写对通用类型别名的引用与编写别名类型的结果实例化具有完全相同的效果.

类型别名声明的BindingIdentifier可能不是预定义的类型名称之一(第3.8.1节).

类型别名中指定的类型依赖于该类型别名是错误的. 类型具有以下依赖性:

  • 类型别名直接取决于其别名的类型.
  • 类型引用直接取决于所引用的类型以及每个类型参数(如果有).
  • 并集或交集类型直接取决于每种构成类型.
  • 数组类型直接取决于其元素类型.
  • 元组类型直接取决于其每个元素类型.
  • 类型查询直接取决于引用实体的类型.

给定这个定义,一个类型所依赖的完整类型集就是直接依赖关系的传递闭包. 请注意,对象类型文字,函数类型文字和构造函数类型文字不依赖于其中引用的类型,因此允许通过类型别名循环引用自身.

类型别名声明的一些示例:

type StringOrNumber = string | number;  
type Text = string | { text: string };  
type NameLookup = Dictionary<string, Person>;  
type ObjectStatics = typeof Object;  
type Callback<T> = (data: T) => void;  
type Pair<T> = [T, T];  
type Coordinates = Pair<number>;  
type Tree<T> = T | { left: Tree<T>, right: Tree<T> };

接口类型与对象类型文字的类型别名有很多相似之处,但是由于接口类型提供了更多的功能,因此它们通常比类型别名更可取. 例如,接口类型

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

可以写为类型别名

type Point = {  
    x: number;  
    y: number;  
};

但是,这样做意味着失去了以下功能:

  • 可以在extend或Implements子句中命名接口,但是不能为对象类型文字提供类型别名.
  • 一个接口可以具有多个合并的声明,但是对象类型文字的类型别名不能.

3.11 Type Relationships

Types in TypeScript have identity, subtype, supertype, and assignment compatibility relationships as defined in the following sections.

3.11.1 Apparent Members

类型的表观成员是在子类型,超类型和分配兼容性关系中观察到的成员,以及在属性访问(第 4.13 ), new操作(第4.14节)和函数调用(第4.15节) 的类型检查中观察到的成员 . 类型的外观成员确定如下:

  • 基本类型Number和所有枚举类型的明显成员是全局接口类型'Number'的明显成员.
  • 基本类型布尔值的表观成员是全局接口类型"布尔值"的表观成员.
  • 基本类型String和所有字符串文字类型的明显成员是全局接口类型'String'的明显成员.
  • 类型参数的表观成员是该类型参数的约束的表观成员(第3.6.1节).
  • 对象类型T的表观成员是以下各项的组合:
    • T的已声明和/或继承的成员.
    • 全局接口类型'Object'的属性不会被T中具有相同名称的属性隐藏.
    • 如果T具有一个或多个调用或构造签名,则全局接口类型'Function'的属性不会被T中具有相同名称的属性隐藏.
  • 联合类型U的表观成员确定如下:
    • U的所有构成类型均具有名为N的表观属性时, U具有相应属性类型的并集类型的表观属性名为N.
    • 当所有构成类型的U具有的表观呼叫签名与一个参数列表P,U具有与参数列表P,那就是相应的返回类型的联合返回类型的表观呼叫签名. 呼叫签名以与第一种构成类型相同的顺序出现.
    • U的所有构成类型均具有带有参数列表P的明显构造体签名时, U具有带有参数列表P和作为各自返回类型的并集的返回类型的明显构造体签名. 构造签名的出现顺序与第一种组成类型相同.
    • U的所有构成类型均具有表观字符串索引签名时, U具有各自字符串索引签名类型的并集类型的表观字符串索引签名.
    • U的所有组成类型均具有表观数字索引签名时, U具有各自数字索引签名类型的并集类型的表观数字索引签名.
  • 相交类型I的外观成员确定如下:
    • I的多个构成类型之一具有名为N的外观属性时, 具有名为N的各个属性类型的交集类型的外观属性.
    • I的一个或多个构成类型具有呼叫签名S时具有明显的呼叫签名S. 签名按I中组成类型的顺序排列,作为每种组成类型的签名的串联.
    • I的一个或多个构成类型具有构造签名S时具有明显的构造签名S. 签名按I中组成类型的顺序排列,作为每种组成类型的签名的串联.
    • I的一种或多种构成类型具有明显的字符串索引签名时, 具有相应的字符串索引签名类型的交集类型的明显的字符串索引签名.
    • 当一个或多个组成类型的有一个明显的数字索引签名,I具有的交叉型的相应数字签名的索引类型中的一个明显的数字索引签名.

如果类型不是上述之一,则认为它没有明显的成员.

实际上,类型的外观成员使其成为"对象"或"功能"接口的子类型,除非该类型定义的成员与"对象"或"功能"接口的成员不兼容(例如,如果type定义的属性与" Object"或" Function"接口中的属性同名,但其类型不是" Object"或" Function"接口中的子类型.

一些例子:

var o: Object = { x: 10, y: 20 };         // Ok  
var f: Function = (x: number) => x * x;   // Ok  
var err: Object = { toString: 0 };        // Error

最后一个赋值是一个错误,因为对象文字的'toString'方法与'Object'的方法不兼容.

3.11.2 Type and Member Identity

Two types are considered identical when

  • they are both the Any type,
  • they are the same primitive type,
  • they are the same type parameter,
  • they are union types with identical sets of constituent types, or
  • they are intersection types with identical sets of constituent types, or
  • they are object types with identical sets of members.

Two members are considered identical when

  • they are public properties with identical names, optionality, and types,
  • they are private or protected properties originating in the same declaration and having identical types,
  • they are identical call signatures,
  • they are identical construct signatures, or
  • they are index signatures of identical kind with identical types.

Two call or construct signatures are considered identical when they have the same number of type parameters with identical type parameter constraints and, after substituting type Any for the type parameters introduced by the signatures, identical number of parameters with identical kind (required, optional or rest) and types, and identical return types.

Note that, except for primitive types and classes with private or protected members, it is structure, not naming, of types that determines identity. Also, note that parameter names are not significant when determining identity of signatures.

Private and protected properties match only if they originate in the same declaration and have identical types. Two distinct types might contain properties that originate in the same declaration if the types are separate parameterized references to the same generic class. In the example

class C<T> { private x: T; }

interface X { f(): string; }

interface Y { f(): string; }

var a: C<X>;  
var b: C<Y>;

the variables 'a' and 'b' are of identical types because the two type references to 'C' create types with a private member 'x' that originates in the same declaration, and because the two private 'x' members have types with identical sets of members once the type arguments 'X' and 'Y' are substituted.

3.11.3 Subtypes and Supertypes

S是类型T子类型 ,以及TS超类型 ,如果S有没有多余的性能相对于T( 3.11.5 )和下列之一是真实的:

  • ST是相同的类型.
  • T是Any类型.
  • S是未定义的类型.
  • S是Null类型,而T不是Undefined类型.
  • S是枚举类型, T是原始类型Number.
  • S是字符串文字类型,而T是原始类型String.
  • S是联合类型,并且S的每个构成类型是T的子类型.
  • S是交叉路口型和S中的至少一种成分类型为T的子类型.
  • T是并集类型, ST的至少一个组成类型的子类型.
  • T是交集类型, ST的每个组成类型的子类型.
  • S是类型参数,并且S的约束是T的子类型.
  • S是对象类型,交集类型,枚举类型或Number,Boolean或String原语类型, T是对象类型,并且对于T中的每个成员M ,下列条件之一为真:
    • M是一个属性, S是一个明显的属性N ,其中
      • MN具有相同的名称,
      • N的类型是M的子类型,
      • 如果M是必需属性,则N也是必需属性,并且
      • MN都是公共的, MN都是私有的,并且起源于同一声明, MN都受保护,起源于同一声明,或者M受保护,并且N在从以下类派生的类中声明: M被声明.
    • M是一个非专门呼叫或构建体签名和S的表观呼叫或构建体签名N,其中,当MN型使用任何作为所有类型参数的参数类型宣布MN(如果有的话)被实例化,
      • 签名属于同一种类(调用或构造),
      • M具有休息参数,或者N中非可选参数的数量小于或等于M中的参数总数,
      • 对于两个签名中都存在的参数位置, N中的每个参数类型都是M中相应参数类型的子类型或超类型.
      • M的结果类型是无效的,或N的结果类型是该M的亚型.
    • M是类型U的字符串索引签名,而U是Any类型,或者S具有明显类型的字符串索引签名,该类型是U的子类型.
    • M是类型U的数字索引签名,而U是Any类型,或者S具有作为U的子类型的类型的表观字符串或数字索引签名.

比较调用或构造签名时,将忽略参数名称,其余参数对应于其余参数元素类型的可选参数的无限制扩展.

注意,在确定子类型和超类型关系时,专用的调用和构造签名(第3.9.2.4节)并不重要.

另请注意,类型参数不被视为对象类型. 因此,类型参数T的唯一子类型是T本身以及直接或间接约束为T的其他类型参数.

3.11.4 Assignment Compatibility

Types are required to be assignment compatible in certain circumstances, such as expression and variable types in assignment statements and argument and parameter types in function calls.

S分配给一个类型T,T可分配的选自 S,如果S有没有多余的性能相对于T( 3.11.5 )和下列之一是真实的:

  • ST是相同的类型.
  • S or T is the Any type.
  • S是未定义的类型.
  • S是Null类型,而T不是Undefined类型.
  • ST是枚举类型,另一个是原始类型Number.
  • S是字符串文字类型,而T是原始类型String.
  • S是联合类型,并且S的每个组成类型都可以分配给T.
  • S是交叉路口型和S中的至少一种成分类型可分配至T.
  • T是联合类型,并且S可分配给T的至少一个组成类型.
  • T是交集类型,并且S可分配给T的每个组成类型.
  • S是类型参数,并且S的约束可分配给T.
  • S是对象类型,交集类型,枚举类型或Number,Boolean或String原语类型, T是对象类型,并且对于T中的每个成员M ,下列条件之一为真:
    • M是一个属性, S是一个明显的属性N ,其中
      • MN具有相同的名称,
      • N的类型可分配给M的类型
      • 如果M是必需属性,则N也是必需属性,并且
      • MN都是公共的, MN都是私有的,并且起源于同一声明, MN都受保护,起源于同一声明,或者M受保护,并且N在从以下类派生的类中声明: M被声明.
    • M是可选属性, S没有与M相同名称的明显属性.
    • M是一个非专门呼叫或构建体签名和S的表观呼叫或构建体签名N,其中,当MN型使用任何作为所有类型参数的参数类型宣布MN(如果有的话)被实例化,
      • 签名属于同一种类(调用或构造),
      • M具有休息参数,或者N中非可选参数的数量小于或等于M中的参数总数,
      • 对于两个签名中都存在的参数位置, N中的每个参数类型都可以分配给M中的相应参数类型或从M中的对应参数类型分配,
      • M的结果类型为Void,或者N的结果类型可分配给M的结果类型.
    • M是类型U的字符串索引签名,而U是Any类型,或者S具有可分配给U的类型的表观字符串索引签名.
    • M是类型U的数字索引签名, U是Any类型,或者S具有可分配给U的明显的字符串或数字索引签名.

比较调用或构造签名时,将忽略参数名称,其余参数对应于其余参数元素类型的可选参数的无限制扩展.

Note that specialized call and construct signatures (section 3.9.2.4) are not significant when determining assignment compatibility.

分配兼容性和子类型化规则的不同之处仅在于:

  • 任何类型都可以分配给所有类型,但不能分配给所有类型,
  • 原始类型Number可以分配给所有枚举类型,但不能为其子类型,并且
  • 没有特定属性的对象类型可分配给该属性是可选的对象类型.

分配兼容性规则意味着,在分配值或传递参数时,可选属性必须要么存在且具有兼容类型,要么根本不存在. 例如:

function foo(x: { id: number; name?: string; }) { }

foo({ id: 1234 });                 // Ok  
foo({ id: 1234, name: "hello" });  // Ok  
foo({ id: 1234, name: false });    // Error, name of wrong type  
foo({ name: "hello" });            // Error, id required but missing

3.11.5 Excess Properties

The subtype and assignment compatibility relationships require that source types have no excess properties with respect to their target types. The purpose of this check is to detect excess or misspelled properties in object literals.

A source type S is considered to have excess properties with respect to a target type T if

  • S is a fresh object literal type, as defined below, and
  • S has one or more properties that aren't expected in T.

A property P is said to be expected in a type T if one of the following is true:

  • T is not an object, union, or intersection type.
  • T is an object type and
    • T has a property with the same name as P,
    • T has a string or numeric index signature,
    • T has no properties, or
    • T is the global type 'Object'.
  • T is a union or intersection type and P is expected in at least one of the constituent types of T.

为对象文字推断的类型(如第 4.5 节中所述 )被认为是新鲜的对象文字类型 . 当对象文字类型被扩展( 3.12 )或类型断言中的表达式类型( 4.16 )时,新鲜度消失.

考虑以下示例:

interface CompilerOptions {  
    strict?: boolean;  
    sourcePath?: string;  
    targetPath?: string;  
}

var options: CompilerOptions = {  
    strict: true,  
    sourcepath: "./src",  // Error, excess or misspelled property  
    targetpath: "./bin"   // Error, excess or misspelled property  
};

'CompilerOptions'类型仅包含可选属性,因此,无需检查多余的属性, 任何对象文字都可以分配给'options'变量(因为拼写错误的属性将被视为其他名称的多余属性).

如果期望有多余的属性,则可以将索引签名添加到目标类型以指示意图:

interface InputElement {  
    name: string;  
    visible?: boolean;  
    [x: string]: any;            // Allow additional properties of any type  
}

var address: InputElement = {  
    name: "Address",  
    visible: true,  
    help: "Enter address here",  // Allowed because of index signature  
    shortcut: "Alt-A"            // Allowed because of index signature  
};

3.11.6 Contextual Signature Instantiation

在函数调用中进行类型实参推断期间(第 4.15.2 ),在某些情况下,有必要在参数的非泛型调用签名的上下文中实例化实参表达式的泛型调用签名,以便可以进行进一步的推断. . 一个通用呼叫签名A 非通用呼叫签名B 的上下文实例如下:

  • 使用所描述的方法3.11.7 ,对于A的类型参数的推论是从每个参数类型在B到相应的参数类型由所述的那些参数的位置是存在于这两个签名,其中其余的参数对应于无限扩张其余参数元素类型的可选参数.
  • 每个类型参数的推断类型参数是对该类型参数进行的推理的并集类型. 但是,如果联合类型不满足type参数的约束,则推断的type参数将成为约束.

3.11.7 Type Inference

In certain contexts, inferences for a given set of type parameters are made from a type S, in which those type parameters do not occur, to another type T, in which those type parameters do occur. Inferences consist of a set of candidate type arguments collected for each of the type parameters. The inference process recursively relates S and T to gather as many inferences as possible:

  • If T is one of the type parameters for which inferences are being made, S is added to the set of inferences for that type parameter.
  • Otherwise, if S and T are references to the same generic type, inferences are made from each type argument in S to each corresponding type argument in T.
  • Otherwise, if S and T are tuple types with the same number of elements, inferences are made from each element type in S to each corresponding element type in T.
  • Otherwise, if T is a union or intersection type:
    • First, inferences are made from S to each constituent type in T that isn't simply one of the type parameters for which inferences are being made.
    • If the first step produced no inferences then if T is a union type and exactly one constituent type in T is simply a type parameter for which inferences are being made, inferences are made from S to that type parameter.
  • Otherwise, if S is a union or intersection type, inferences are made from each constituent type in S to T.
  • Otherwise, if S and T are object types, then for each member M in T:
    • If M is a property and S contains a property N with the same name as M, inferences are made from the type of N to the type of M.
    • If M is a call signature and a corresponding call signature N exists in S, N is instantiated with the Any type as an argument for each type parameter (if any) and inferences are made from parameter types in N to the corresponding parameter types in M for positions that are present in both signatures, and from the return type of N to the return type of M.
    • If M is a construct signature and a corresponding construct signature N exists in S, N is instantiated with the Any type as an argument for each type parameter (if any) and inferences are made from parameter types in N to the corresponding parameter types in M for positions that are present in both signatures, and from the return type of N to the return type of M.
    • If M is a string index signature and S contains a string index signature N, inferences are made from the type of N to the type of M.
    • If M is a numeric index signature and S contains a numeric index signature N, inferences are made from the type of N to the type of M.
    • If M is a numeric index signature and S contains a string index signature N, inferences are made from the type of N to the type of M.

When comparing call or construct signatures, signatures in S correspond to signatures of the same kind in T pairwise in declaration order. If S and T have different numbers of a given kind of signature, the excess first signatures in declaration order of the longer list are ignored.

TODO: Update to reflect improved union and intersection type inference.

3.11.8 Recursive Types

Classes and interfaces can reference themselves in their internal structure, in effect creating recursive types with infinite nesting. For example, the type

interface A { next: A; }

contains an infinitely nested sequence of 'next' properties. Types such as this are perfectly valid but require special treatment when determining type relationships. Specifically, when comparing types S and T for a given relationship (identity, subtype, or assignability), the relationship in question is assumed to be true for every directly or indirectly nested occurrence of the same S and the same T (where same means originating in the same declaration and, if applicable, having identical type arguments). For example, consider the identity relationship between 'A' above and 'B' below:

interface B { next: C; }

interface C { next: D; }

interface D { next: B; }

To determine whether 'A' and 'B' are identical, first the 'next' properties of type 'A' and 'C' are compared. That leads to comparing the 'next' properties of type 'A' and 'D', which leads to comparing the 'next' properties of type 'A' and 'B'. Since 'A' and 'B' are already being compared this relationship is by definition true. That in turn causes the other comparisons to be true, and therefore the final result is true.

When this same technique is used to compare generic type references, two type references are considered the same when they originate in the same declaration and have identical type arguments.

In certain circumstances, generic types that directly or indirectly reference themselves in a recursive fashion can lead to infinite series of distinct instantiations. For example, in the type

interface List<T> {  
    data: T;  
    next: List<T>;  
    owner: List<List<T>>;  
}

'List<T>' has a member 'owner' of type 'List<List<T>>', which has a member 'owner' of type 'List<List<List<T>>>', which has a member 'owner' of type 'List<List<List<List<T>>>>' and so on, ad infinitum. Since type relationships are determined structurally, possibly exploring the constituent types to their full depth, in order to determine type relationships involving infinitely expanding generic types it may be necessary for the compiler to terminate the recursion at some point with the assumption that no further exploration will change the outcome.

3.12 Widened Types

In several situations TypeScript infers types from context, alleviating the need for the programmer to explicitly specify types that appear obvious. For example

var name = "Steve";

infers the type of 'name' to be the String primitive type since that is the type of the value used to initialize it. When inferring the type of a variable, property or function result from an expression, the widened form of the source type is used as the inferred type of the target. The widened form of a type is the type in which all occurrences of the Null and Undefined types have been replaced with the type any.

The following example shows the results of widening types to produce inferred variable types.

var a = null;                 // var a: any  
var b = undefined;            // var b: any  
var c = { x: 0, y: null };    // var c: { x: number, y: any }  
var d = [ null, undefined ];  // var d: any[]

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 augments JavaScript expressions with the following constructs:

  • Optional parameter and return type annotations in function expressions and arrow functions.
  • Type arguments in function calls.
  • 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

表达式被分类为引用 . 引用是被允许作为赋值目标的表达式的子集. 具体来说,引用是标识符(第 4.3 ),括号(第4.8节)和属性访问(第4.13节)的组合. 本章中描述的所有其他表达式构造都归类为值.

4.2 The this Keyword

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

在所有其他上下文中,引用this导致编译时错误.

请注意,箭头函数(第4.11节)没有this参数,而是保留了其封闭上下文的this .

4.3 Identifiers

当表达式是IdentifierReference时 ,该表达式引用名称最嵌套的名称空间,类,枚举,函数,变量或参数,其名称(范围 2.4 )包括引用的位置. 此类表达式的类型是与引用实体相关联的类型:

  • 对于名称空间,是与名称空间实例关联的对象类型.
  • 对于类,与构造函数对象关联的构造类型.
  • 对于枚举,与枚举对象关联的对象类型.
  • 对于功能,是与功能对象关联的功能类型.
  • 对于变量,变量的类型.
  • 对于参数,参数的类型.

引用变量或参数的标识符表达式被分类为引用. 引用任何其他种类的实体的标识符表达式被分类为值(因此不能成为分配的目标).

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 methods and get and set accessors.

  PropertyDefinition: ( Modified )
   IdentifierReference
   CoverInitializedName
   PropertyName:AssignmentExpression
   PropertyNameCallSignature{FunctionBody}
   GetAccessor
   SetAccessor

  GetAccessor:
   getPropertyName()TypeAnnotationopt{FunctionBody}

  SetAccessor:
   setPropertyName(BindingIdentifierOrPatternTypeAnnotationopt){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 shorthand property assignment of the form

prop

is equivalent to

prop : prop

Likewise, a property assignment of the form

f ( ... ) { ... }

is equivalent to

f : function ( ... ) { ... }

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, if the contextual type contains a numeric index signature, and if 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 type of Expr.

get访问器声明的处理方式与不带参数的普通函数声明(第 6.1 )相同. 设置访问者声明的处理方式与具有单个参数和Void返回类型的普通函数声明的处理方式相同. 同时为属性声明get和set访问器时:

  • 如果两个访问器都包含类型注释,则指定的类型必须相同.
  • 如果只有一个访问器包含类型注释,则另一个访问器的行为就好像它具有相同的类型注释.
  • 如果两个访问器都不包含类型注释,则get访问器的推断返回类型将成为set访问器的参数类型.

如果为属性声明了get访问器,则get访问器的返回类型将成为属性的类型. 如果仅为属性声明集合访问器,则集合访问器的参数类型(如果不存在类型注释,则可以为Any类型)成为属性的类型.

当对象文字通过包含字符串索引签名的类型在上下文中键入时,对象文字的结果类型包括字符串索引签名,该字符串索引签名具有在对象文字中声明的属性的类型的并集类型,或者为Undefined类型(如果存在)对象文字为空. 同样,当对象文字通过包含数字索引签名的类型在上下文中键入时,对象文字的结果类型包括数字索引签名,该数字索引签名具有声明的数字命名属性的类型的联合类型(第3.9.4节)在对象文字中,如果对象文字未声明任何数字命名的属性,则为Undefined类型.

如果属性分配的PropertyName是不表示众所周知的符号( 2.2.3 )的计算的属性名称,则该构造被视为动态属性分配 . 以下规则适用于动态属性分配:

  • 动态属性分配不会在对象文字的类型中引入属性.
  • 动态属性分配的属性名称表达式必须是Any类型或String,Number或Symbol原语类型.
  • 如果属性名称表达式的类型为Any或Number原语类型,则与动态属性分配关联的名称被视为数字属性名称.

4.6 Array Literals

An array literal

[ expr1, expr2, ..., exprN ]

表示取决于上下文的数组类型(第 3.3.2 )或元组类型(第3.3.3节)的值.

非空数组文字中的每个元素表达式的处理如下:

  • 如果数组文字不包含任何扩展元素,并且数组文字通过类型T在上下文中进行了类型化(第4.23节),并且T具有数字名称N的属性,其中N是数组文字中元素表达式的索引,元素表达式是根据该属性的类型在上下文中键入的.
  • 否则,如果数组文字是由带有数字索引签名的类型T在上下文中键入的,则元素表达式是由数字索引签名的类型在上下文中键入的.
  • 否则,元素表达式不会在上下文中键入.

数组文字表达式的结果类型确定如下:

  • 如果数组文字为空,则结果类型为元素类型为Undefined的数组类型.
  • 否则,如果数组文字不包含任何散布元素,并且使用类似元组的类型在上下文中进行类型化(第3.3.3节),则结果类型为根据元素表达式的类型构造的元组类型.
  • 否则,如果数组文字不包含任何散布元素,并且是解构分配中的数组分配模式(第4.21.1节),则结果类型为根据元素表达式的类型构造的元组类型.
  • 否则,结果类型将是一个数组类型,其元素类型是未扩展元素表达式的类型与扩展元素表达式的数字索引签名类型的并集.

扩展元素必须指定类似数组类型的表达式(第3.3.2节),否则会发生错误.

TODO:编译器当前不支持将扩展运算符应用于字符串(将字符串的各个字符扩展为字符串数组). 最终将允许这样做,但前提是代码生成目标是ECMAScript 2015或更高版本.

TODO:将迭代器扩展到数组文字中的文档.

上面的规则意味着数组文字始终是数组类型的,除非使用类似元组的类型在上下文中键入它. 例如

var a = [1, 2];                          // number[]  
var b = ["hello", true];                 // (string | boolean)[]  
var c: [number, string] = [3, "three"];  // [number, string]

当输出目标为ECMAScript 3或5时,包含扩展元素的数组文字将重写为concat方法的调用. 例如,作业

var a = [2, 3, 4];  
var b = [0, 1, ...a, 5, 6];

被重写为

var a = [2, 3, 4];  
var b = [0, 1].concat(a, [5, 6]);

4.7 Template Literals

TODO: Template literals.

4.8 Parentheses

A parenthesized expression

( expr )

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

4.9 The super Keyword

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

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

超级调用在this引用的实例上调用基类的构造函数. 使用基类构造函数类型的构造签名作为用于过载解析的候选签名的初始集合,将超级调用作为函数调用(第4.15节)进行处理. 类型参数不能在超级调用中明确指定. 如果基类是泛型类,则用于处理超级调用的类型参数始终是在引用基类的extends子句中指定的类型参数.

超级调用表达式的类型为Void.

8.7.2节中指定了为超级调用生成的JavaScript代码.

4.9.2 Super Property Access

超级属性访问由关键字super后跟点和标识符组成. 超级属性访问用于从派生类访问基类成员函数,并且在this (第 4.2 )引用派生类实例或派生类构造函数的上下文中允许访问 . 特别:

  • 在一个构造函数,实例成员函数,实例成员访问器,或实例成员变量初始值,其中this引用派生类例如,超级属性访问被允许并必须指定基类的公共实例成员函数.
  • 在一个静态成员函数或静态成员存取this引用派生类的构造函数对象,超级属性访问被允许并必须指定基类的公共静态成员函数.

在其他上下文中不允许超级属性访问,并且在超级属性访问中无法访问其他类型的基类成员. 注意,超级属性访问不允许嵌套在上述构建体中的内部函数表达式,因为this是类型的任何在这样的函数的表达式.

超级属性访问通常用于访问派生类成员函数中重写的基类成员函数. 有关此示例,请参见8.4.2节.

8.7.2节中指定了为超级属性访问而生成的JavaScript代码.

TODO:更新部分以在超级属性访问中包括括号符号.

4.10 Function Expressions

Function expressions are extended from JavaScript to optionally include parameter and return type annotations.

  FunctionExpression: ( Modified )
   functionBindingIdentifieroptCallSignature{FunctionBody}

6 章中提供的函数声明的描述也适用于函数表达式,但函数表达式不支持重载.

函数表达式的类型是一个对象类型,其中包含单个调用签名,该调用签名具有从函数表达式的签名和主体推断出的参数和返回类型.

当通过类型T在上下文中键入没有类型参数且没有参数类型注释的函数表达式(第4.23节),并且可以从T中提取上下文签名S时,将处理该函数表达式,就好像它已明确指定了参数类型注释为:它们存在于S中 . 参数按位置进行匹配,并且不必具有匹配的名称. 如果函数表达式的参数少于S ,则忽略S中的其他参数. 如果函数表达式的参数多于S ,则所有附加参数均被视为具有Any类型.

同样,当通过函数类型T在上下文中键入没有返回类型注释的函数表达式(第4.23节),并且可以从T中提取上下文签名S时 ,所包含的return语句(第5.10节)中的表达式将通过返回类型在上下文中进行键入.的S.

如下从功能类型T中提取上下文签名S

  • 如果T是仅具有一个调用签名的函数类型,并且该调用签名不是通用的,则S是该签名.
  • 如果T是联合类型,则让UT中具有调用签名的元素类型的集合. 如果U中的每种类型都恰好具有一个呼叫签名,并且该呼叫签名是非泛型的,并且如果所有签名都是相同的(忽略返回类型),则S是具有相同参数和返回类型并集的签名.
  • 否则,无法从T提取上下文签名.

在这个例子中

var f: (s: string) => string = function (s) {  
    return s.toLowerCase();  
};

the function expression is contextually typed by the type of 'f', and since the function expression has no type parameters or type annotations its parameter type information is extracted from the contextual type, thus inferring the type of 's' to be the String primitive type.

4.11 Arrow Functions

Arrow functions are extended from JavaScript to optionally include parameter and return type annotations.

  ArrowFormalParameters: ( Modified )
   CallSignature

6 章中提供的函数声明的描述也适用于箭头函数,但箭头函数不支持重载.

箭头函数的类型与函数表达式相同(第4.10节). 同样,箭头函数的参数和箭头函数主体中的return语句在上下文中的键入方式与函数表达式相同.

当通过函数类型T在上下文中键入带有表达式主体且没有返回类型注释的箭头函数(第4.23节),并且可以从T中提取上下文签名S时,通过返回类型S在上下文中键入表达式主体.

形式的箭头函数表达式

( ... ) => expr

完全等同于

( ... ) => { return expr ; }

此外,表单的箭头函数表达式

id => { ... }  
id => expr

完全等同于

( id ) => { ... }  
( id ) => expr

因此,以下示例都是等效的:

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

函数表达式引入一个新的动态绑定this ,而箭头函数表达式保留其封闭上下文的this . 箭头函数表达式对于编写回调特别有用,否则回调通常具有未定义或意外的this .

在这个例子中

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

TypeScript编译器应用这种类型的转换将箭头函数表达式重写为标准函数表达式.

形式的构造

< T > ( ... ) => { ... }

可以被解析为带有类型参数的箭头函数表达式,或者被应用到没有类型参数的箭头函数的类型断言. 它被解析为前者,但是可以使用括号来选择后者的含义:

< T > ( ( ... ) => { ... } )

4.12 Class Expressions

TODO: Document class expressions.

4.13 Property Access

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

A dot notation property access of the form

object . name

where object 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:

表格的方括号符号属性访问

object [ index ]

其中对象索引是表达式,用于通过给定对象上的索引表达式计算的名称访问属性. 括号符号属性访问在编译时按以下方式处理:

  • 如果index是字符串文字或数字文字,并且对象具有明显的属性(第3.11.1节),其名称由该文字提供(在数字文字的情况下转换为字符串表示形式),则属性访问权限为该属性的类型.
  • 否则,如果对象具有明显的数字索引签名,并且索引的类型为Any,Number原语类型或枚举类型,则属性访问属于该索引签名的类型.
  • 否则,如果对象具有明显的字符串索引签名,并且索引的类型为Any,String或Number原语类型或枚举类型,则属性访问属于该索引签名的类型.
  • 否则,如果index为Any类型,String或Number原语类型或枚举类型,则属性访问类型为Any.
  • 否则,属性访问无效,并发生编译时错误.

TODO:使用符号索引.

上面的规则意味着,使用带有名称名称表示形式的方括号表示法访问属性时,将强类型化属性. 例如:

var type = {  
    name: "boolean",  
    primitive: true  
};

var s = type["name"];       // string  
var b = type["primitive"];  // boolean

元组类型为每个元素分配数字名称,因此,当使用带数字文字的方括号表示法访问时,元素将被强类型化:

var data: [string, number] = ["five", 5];  
var s = data[0];  // string  
var n = data[1];  // number

4.14 The new Operator

A new operation has one of the following forms:

new C  
new C ( ... )  
new C < ... > ( ... )

where C is an expression. The first form is equivalent to supplying an empty argument list. C 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:

4.15 Function Calls

Function calls are extended from JavaScript to support optional type arguments.

  Arguments: ( Modified )
   TypeArgumentsopt(ArgumentListopt)

A function call takes one of the forms

func ( ... )  
func < ... > ( ... )

其中func是函数类型或Any类型的表达式. 函数表达式后跟一个可选的类型参数列表(第 3.6.2 )和一个参数列表.

如果func是Any类型,或者是没有调用或构造签名但是Function接口的子类型的对象类型,则该调用是未类型化的函数call . 在无类型的函数调用中,不允许使用任何类型的参数,参数表达式可以是任何类型和数字,没有为参数表达式提供上下文类型,并且结果始终是Any类型.

如果func具有明显的调用签名(第3.11.1节),则该调用为类型化函数调用 . TypeScript在类型函数调用中采用重载解析 ,以支持具有多个调用签名的函数. 此外,TypeScript可以执行类型参数推断以自动确定泛型函数调用中的类型参数.

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

TODO: Describe use of 重载解析中的通配符函数类型.

类型化函数调用的编译时处理包括以下步骤:

  • 首先,根据声明顺序,从函数类型中的调用签名构建候选签名列表. 对于类和接口,继承的签名被视为以extends子句顺序遵循显式声明的签名.
    • 非通用签名在以下情况下是候选
      • 函数调用没有类型参数,并且
      • 该签名适用于函数调用的参数列表.
    • 泛型签名是函数调用中不带类型实参的候选对象,当
      • 每个类型参数成功进行类型推断(第4.15.2节),
      • 一旦将推断出的类型参数替换为其关联的类型参数,则签名对于函数调用的参数列表适用.
    • 泛型签名是函数调用中带有类型实参的候选对象,当
      • 签名的类型参数数量与类型参数列表中提供的数量相同,
      • 类型参数满足其约束,并且
      • 一旦将类型参数替换为其关联的类型参数,则签名对于函数调用的参数列表适用.
  • 如果候选签名列表为空,则函数调用为错误.
  • 否则,如果候选列表包含一个或多个签名,而每个参数表达式的类型是每个对应参数类型的子类型,则这些签名中的第一个的返回类型将成为函数调用的返回类型.
  • 否则,候选列表中第一个签名的返回类型将成为函数调用的返回类型.

在以下情况下,签名被称为相对于参数列表的适用签名:

  • 参数的数量不少于必需的参数的数量,
  • 参数的数量不大于参数的数量,并且
  • 对于每个参数表达式e及其对应的参数P,eP的类型进行上下文类型化(第4.23节)时,不会发生任何错误,并且e的类型可分配给P的类型(第3.11.4节 ).

TODO: 在函数调用中传播运算符,并将迭代器传播到函数调用中.

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

TODO: Update type argument inference and overload resolution rules.

类型参数推论为每个类型参数产生一组候选类型. 给定类型参数T和一组候选类型,实际推断的类型参数确定如下:

  • 如果候选参数类型的集合为空,则T的推断类型参数为T的约束.
  • 否则,如果至少一个候选类型是所有其他候选类型的超类型,则让C表示第一个此类候选类型的加宽形式(第3.12节). 如果C满足T的约束,则T的推断类型参数为C. 否则, T的推断类型参数是T的约束.
  • 否则,如果没有候选类型是所有其他候选类型的超类型,则类型推断将失败,并且不会为T推断类型实参.

为了计算候选类型,参数列表按以下方式处理:

  • 最初,所有推断出的类型参数都被认为是未固定的一组空的候选类型.
  • 从左到右,每个参数表达式e都由其对应的参数类型P 推论地键入 ,可能导致某些推断的类型论点变得固定 ,并对来自该类型的未固定的推断的类型论点进行候选类型推断(第3.11.7节).计算eP.

的由类型T推论键入一个表达式e的过程是相同的用T上下文输入E,以下情况除外:

  • 如果e中包含的表达式是上下文类型的,则改为推论类型.
  • 当推导类型的函数表达式(第4.10节)并且在该表达式中分配给参数的类型引用对其进行推断的类型参数时,相应的推断类型实参将变为固定,并且不再对其进行任何候选推断.
  • 如果e是仅包含一个泛型调用签名且不包含其他成员的函数类型的表达式,并且T是仅具有一个非泛型调用签名且没有其他成员的函数类型的表达式,则对由该类引用的类型参数进行的任何推断T的呼叫签名的参数是固定的 ,并且e的类型更改为函数类型,其中e的呼叫签名在T的呼叫签名的上下文中实例化(第3.11.6节).

一个例子:

function choose<T>(x: T, y: T): T {  
    return Math.random() < 0.5 ? x : y;  
}

var x = choose(10, 20);     // Ok, x of type number  
var y = choose("Five", 5);  // Error

在第一次调用" choose"时,从" number"到" T"有两个推论,每个参数一个. 这样,就可以推断出" T"代表" number",而呼叫等同于

var x = choose<number>(10, 20);

在对" choose"的第二次调用中,对第一个参数从类型" string"到" T"进行推断,对第二个参数从类型" number"到" T"进行推断. 由于"字符串"和"数字"都不是另一个的超类型,因此类型推断将失败. 这意味着没有适用的签名,并且函数调用是错误.

在这个例子中

function map<T, U>(a: T[], f: (x: T) => U): U[] {  
    var result: U[] = [];  
    for (var i = 0; i < a.length; i++) result.push(f(a[i]));  
    return result;  
}

var names = ["Peter", "Paul", "Mary"];  
var lengths = map(names, s => s.length);

对" map"的调用中对" T"和" U"的推论如下:对于第一个参数,推论从类型" string []"(类型" names")到类型" T" []",推断" T"的"字符串". 对于第二个参数,箭头表达式's => s.length'的推论输入会导致'T'变得固定,从而推断出的类型'string'可以用于参数's'. 然后可以确定箭头表达式的返回类型,并从类型'(s:字符串)=>数字到类型'(x:T)=> U'进行推断,从而推断出'U'的'数字' '. 因此,对"地图"的调用等同于

var lengths = map<string, number>(names, s => s.length);

因此,"长度"的结果类型为"数字[]".

在这个例子中

function zip<S, T, U>(x: S[], y: T[], combine: (x: S) => (y: T) => U): U[] {  
    var len = Math.max(x.length, y.length);  
    var result: U[] = [];  
    for (var i = 0; i < len; i++) result.push(combine(x[i])(y[i]));  
    return result;  
}

var names = ["Peter", "Paul", "Mary"];  
var ages = [7, 9, 12];  
var pairs = zip(names, ages, s => n => ({ name: s, age: n }));

在对" zip"的调用中对" S"," T"和" U"的推论如下:使用前两个参数,对" S"的" string"和对" T"的" number"进行推论. 对于第三个参数,外箭头表达式的推论类型会导致" S"变得固定,从而可以将推论类型" string"用于参数" s". 当函数表达式被推论类型时,其返回表达式也被推论类型. 因此,推论性地键入了内部箭头函数,从而使" T"变得固定,从而可以将推论类型" number"用作参数" n". 然后可以确定内部箭头函数的返回类型,这又确定了从外部箭头函数返回的函数的返回类型,并根据类型'(s:string)=>(n:number)进行推断. => {名称:string; age:number}'转换为类型'(x:S)=>(y:T)=> R',从而推断出'{{name:string; 年龄:数字}'代表'R'. 因此,对" zip"的调用等同于

var pairs = zip<string, number, { name: string; age: number }>(  
    names, ages, s => n => ({ name: s, age: n }));

因此,结果对的类型为" {name:string; 年龄:数字} []'.

4.15.3 Grammar Ambiguities

Arguments产生(第 4.15 )中包含类型实 参会引起表达式语法的某些歧义. 例如,语句

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

可以解释为对带有两个参数" g <A"和" B>(7)"的" f"的调用. 或者,可以将其解释为使用一个参数调用" f",这是使用两个类型参数和一个常规参数调用通用函数" g".

语法歧义可通过以下方式解决:在标记序列的一种可能解释是Arguments产生的上下文中,如果标记的初始序列形成语法上正确的TypeArguments产生,并且后跟一个' ( '标记,则该序列令牌的数量将被处理为Arguments生产,而其他可能的解释将被丢弃,否则,令牌序列将不被视为Arguments生产.

此规则意味着对上面的" f"的调用被解释为具有一个参数的调用,这是对具有两个类型参数和一个常规参数的通用函数" g"的调用. 但是,这些陈述

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

都被解释为带有两个参数的对" f"的调用.

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

在形式为< T > e的类型断言表达式中, eT上下文中键入(第 4.23 ),并且* e *的结果类型需要分配给T ,或者需要T分配给扩展形式产生e的类型,否则将发生编译时错误. 结果的类型为T.

类型断言在两个方向上检查分配兼容性. 因此,类型断言允许进行可能正确但未知的正确类型转换. 在这个例子中

class Shape { ... }

class Circle extends Shape { ... }

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

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

类型注释指示'createShape'函数可能返回'Circle'(因为'Circle'是'Shape'的子类型),但不知道这样做(因为其返回类型为'Shape'). 因此,需要一个类型断言来将结果视为" Circle".

如上所述,在运行时不检查类型断言,并且由程序员来防止错误,例如使用instanceof运算符:

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

待办事项: 以操作员身份记录.

4.17 JSX Expressions

TODO: Document JSX expressions.

4.18 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.18.1 The ++ and -- operators

这些运算符以前缀或后缀形式要求其操作数的类型为Any,Number基本类型或枚举类型,并被分类为引用(第 4.1 ). 它们产生Number原语类型的结果.

4.18.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.18.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.18.4 The delete Operator

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

4.18.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.7).

4.18.6 The typeof Operator

" typeof"运算符采用任何类型的操作数,并产生String基本类型的值. 在需要类型的位置,'typeof'也可以在类型查询中使用(第 3.8.10 )以生成表达式的类型.

var x = 5;  
var y = typeof x;  // Use in an expression  
var z: typeof x;   // Use in a type query

在上面的示例中," x"的类型为"数字"," y"的类型为"字符串",因为在表达式中使用时," typeof"会生成字符串类型的值(在这种情况下为字符串"数字") ,而'z'是'number'类型的,因为在类型查询中使用'typeof'可以获取表达式的类型.

4.19 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 other types (the Other column in the tables) are provided.

4.19.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 Other
Any Number Number
Boolean
Number Number Number
String
Other

TODO: Document the exponentation operator.

4.19.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 Other
Any Any Any Any String Any
Boolean Any String
Number Any Number String
String String String String String String
Other 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.19.3 The <, >, <=, >=, ==, !=, ===, and !== operators

These operators require one or both of the operand types to be assignable to the other. The result is always of the Boolean primitive type.

Any Boolean Number String Other
Any Boolean Boolean Boolean Boolean Boolean
Boolean Boolean Boolean
Number Boolean Boolean
String Boolean Boolean
Other Boolean Boolean

4.19.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.19.5 The in operator

The in operator requires the left operand to be of type Any, the String primitive type, or the Number 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.19.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 Other
Any Any Boolean Number String Other
Boolean Any Boolean Number String Other
Number Any Boolean Number String Other
String Any Boolean Number String Other
Other Any Boolean Number String Other

4.19.7 The || operator

The || operator permits the operands to be of any type.

如果|| expression是上下文类型的(第 4.23 ),操作数也可以使用相同类型的上下文类型. 否则,将不会在上下文中键入左操作数,而在上下文中将根据左操作数的类型来键入右操作数.

结果的类型是两种操作数类型的并集类型.

Any Boolean Number String Other
Any Any Any Any Any Any
Boolean Any Boolean N B S
Number Any N B Number S
String Any S B S N
Other Any B O N O

4.20 The Conditional Operator

In a conditional expression of the form

test ? expr1 : expr2

the test expression may be of any type.

如果条件表达式是上下文类型的(第 4.23 ),则expr1expr2会使用相同类型的上下文类型. 否则,不会在上下文中键入expr1expr2 .

结果的类型是expr1expr2类型的并集类型.

4.21 Assignment Operators

An assignment of the form

v = expr

要求v被分类为参考(第 4.1 )或分配模式(第4.21.1节). expr表达式由v的类型进行上下文类型化(第4.23节),并且expr的类型必须可分配给v的类型(第3.11.4节v的类型,否则会发生编译时错误. 结果是类型为expr的值.

形式的复合赋值

v ??= expr

其中?? =是复合赋值运算符之一

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

与相应的非复合运算符相同,并具有相同类型的值. 的化合物,还分配需要v到被分类为参考(部分4.1 )和非化合物的操作的类型可分配到v的类型. 请注意,在复合分配中,不允许v是分配模式.

4.21.1 Destructuring Assignment

A destructuring assignment is an assignment operation in which the left hand operand is a destructuring assignment pattern as defined by the AssignmentPattern production in the ECMAScript 2015 specification.

In a destructuring assignment expression, the type of the expression on the right must be assignable to the assignment target on the left. An expression of type S is considered assignable to an assignment target V if one of the following is true:

TODO: Update to specify behavior when assignment element E is a rest element.

在包含默认值的分配属性或元素中,默认值的类型必须可分配给分配属性或元素中给定的目标.

当输出目标是ECMAScript 2015或更高版本时,解构变量分配在发出的JavaScript代码中保持不变. 当输出目标为ECMAScript 3或5时,解构变量分配将重写为一系列简单分配. 例如,销毁分配

var x = 1;  
var y = 2;  
[x, y] = [y, x];

被重写为简单的变量分配

var x = 1;  
var y = 2;  
_a = [y, x], x = _a[0], y = _a[1];  
var _a;

4.22 The Comma Operator

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

4.23 Contextually Typed Expressions

Type checking of an expression is improved in several contexts by factoring in the type of the destination of the value computed by the expression. In such situations, the expression is said to be contextually typed by the type of the destination. An expression is contextually typed in the following circumstances:

  • In a variable, parameter, binding property, binding element, or member declaration, an initializer expression is contextually typed by
  • 在具有返回类型批注的函数声明,函数表达式,箭头函数,方法声明或get访问器声明的主体中,返回表达式根据返回类型批注中给出的类型在上下文中键入.
  • 在没有返回类型注释的函数表达式或箭头函数的主体中,如果函数表达式或箭头函数是由具有一个唯一调用签名的函数类型在上下文中键入的,并且如果该调用签名是非泛型的,则返回表达式为根据该调用签名的返回类型在上下文中进行键入.
  • 在构造函数声明的主体中,返回表达式由包含的类类型在上下文中键入.
  • 在没有返回类型批注的get访问器的主体中,如果存在匹配的集合访问器且该集合访问器具有参数类型批注,则返回表达式将根据集合访问器的参数类型批注中给出的类型在上下文中键入.
  • 在类型化的函数调用中,参数表达式由其对应的参数类型在上下文中进行类型化.
  • 在上下文类型的对象文字中,每个属性值表达式的上下文类型为
    • 上下文类型中具有匹配名称的属性的类型(如果有),否则
    • 对于以数字命名的属性,则为上下文类型的数字索引类型(如果有),否则
    • 上下文类型的字符串索引类型(如果有).
  • 在不包含扩展元素的上下文类型的数组文字表达式中,索引N处的元素表达式由
    • 上下文类型中数字名称为N的属性的类型(如果有),否则
    • 上下文类型的数字索引类型(如果有).
  • 在包含一个或多个散布元素的上下文类型的数组文字表达式中,索引N处的元素表达式通过上下文类型的数字索引类型(如果有)在上下文中进行类型化.
  • 在上下文类型的带括号的表达式中,所包含的表达式在上下文上使用相同的类型.
  • 在类型断言中,表达式由指示的类型在上下文中进行类型化.
  • 在||中 运算符表达式,如果表达式是上下文类型的,则操作数将使用相同类型的上下文类型. 否则,将根据左表达式的类型在上下文中键入右表达式.
  • 在上下文类型的条件运算符表达式中,操作数由相同类型在上下文中类型化.
  • 在赋值表达式中,右手表达式由左手表达式的类型在上下文中键入.

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

传递给" setEventHandlers"的对象文字在上下文上被键入为" EventHandlers"类型. 这导致将两个属性分配在上下文中键入为未命名的函数类型'(event:EventObject)=> void',这又导致箭头函数表达式中的'e'参数自动键入为'EventObject'.

4.24 Type Guards

Type guards are particular expression patterns involving the 'typeof' and 'instanceof' operators that cause the types of variables or parameters to be narrowed to more specific types. For example, in the code below, knowledge of the static type of 'x' in combination with a 'typeof' check makes it safe to narrow the type of 'x' to string in the first branch of the 'if' statement and number in the second branch of the 'if' statement.

function foo(x: number | string) {  
    if (typeof x === "string") {  
        return x.length;  // x has type string here  
    }  
    else {  
        return x + 1;     // x has type number here  
    }  
}

The type of a variable or parameter is narrowed in the following situations:

  • In the true branch statement of an 'if' statement, the type of a variable or parameter is narrowed by a type guard in the 'if' condition when true, provided no part of the 'if' statement contains assignments to the variable or parameter.
  • In the false branch statement of an 'if' statement, the type of a variable or parameter is narrowed by a type guard in the 'if' condition when false, provided no part of the 'if' statement contains assignments to the variable or parameter.
  • In the true expression of a conditional expression, the type of a variable or parameter is narrowed by a type guard in the condition when true, provided no part of the conditional expression contains assignments to the variable or parameter.
  • In the false expression of a conditional expression, the type of a variable or parameter is narrowed by a type guard in the condition when false, provided no part of the conditional expression contains assignments to the variable or parameter.
  • In the right operand of a && operation, the type of a variable or parameter is narrowed by a type guard in the left operand when true, provided neither operand contains assignments to the variable or parameter.
  • In the right operand of a || operation, the type of a variable or parameter is narrowed by a type guard in the left operand when false, provided neither operand contains assignments to the variable or parameter.

A type guard is simply an expression that follows a particular pattern. The process of narrowing the type of a variable x by a type guard when true or when false depends on the type guard as follows:

  • A type guard of the form x instanceof C, where x is not of type Any, C is of a subtype of the global type 'Function', and C has a property named 'prototype'
    • 当真, narrows the type of x to the type of the 'prototype' property in C provided it is a subtype of the type of x, or, if the type of x is a union type, removes from the type of x all constituent types that aren't subtypes of the type of the 'prototype' property in C, or
    • 假的时候, has no effect on the type of x.
  • A type guard of the form typeof x === s, where s is a string literal with the value 'string', 'number', or 'boolean',
    • 当真, narrows the type of x to the given primitive type provided it is a subtype of the type of x, or, if the type of x is a union type, removes from the type of x all constituent types that aren't subtypes of the given primitive type, or
    • 假的时候, removes the primitive type from the type of x.
  • A type guard of the form typeof x === s, where s is a string literal with any value but 'string', 'number', or 'boolean',
    • 当为真, if x is a union type, removes from the type of x all constituent types that are subtypes of the string, number, or boolean primitive type, or
    • when false, has no effect on the type of x.
  • A type guard of the form typeof x !== s, where s is a string literal,
    • 当真, narrows the type of x by typeof x === s 假的时候, or
    • 假的时候, narrows the type of x by typeof x === s 当真.
  • A type guard of the form !expr
    • 当真, narrows the type of x by expr 假的时候, or
    • 假的时候, narrows the type of x by expr 当真.
  • A type guard of the form expr1 && expr2
    • 当真, narrows the type of x by expr1 当真 and then by expr2 当真, or
    • 假的时候, narrows the type of x to T1 | T2, where T1 is the type of x narrowed by expr1 假的时候, and T2 is the type of x narrowed by expr1 当真 and then by expr2 假的时候.
  • A type guard of the form expr1 || expr2
    • 当真, narrows the type of x to T1 | T2, where T1 is the type of x narrowed by expr1 当真, and T2 is the type of x narrowed by expr1 假的时候 and then by expr2 当真, or
    • 假的时候, narrows the type of x by expr1 假的时候 and then by expr2 when false.
  • A type guard of any other form has no effect on the type of x.

In the rules above, when a narrowing operation would remove all constituent types from a union type, the operation has no effect on the union type.

Note that type guards affect types of variables and parameters only and have no effect on members of objects such as properties. Also note that it is possible to defeat a type guard by calling a function that changes the type of the guarded variable.

TODO: Document user defined type guard functions.

在这个例子中

function isLongString(obj: any) {  
    return typeof obj === "string" && obj.length > 100;  
}

obj参数在&&运算符的右侧操作数中具有string类型.

在这个例子中

function processValue(value: number | (() => number)) {  
    var x = typeof value !== "number" ? value() : value;  
    // Process number in x  
}

值参数具有类型() => number在所述第一条件表达式和类型number在所述第二条件表达式,并且推断出的类型x的是number .

在这个例子中

function f(x: string | number | boolean) {  
    if (typeof x === "string" || typeof x === "number") {  
        var y = x;  // Type of y is string | number  
    }  
    else {  
        var z = x;  // Type of z is boolean  
    }  
}

x的类型是string | number | boolean string | number | boolean ||的左操作数中的string | number | boolean 运算符, number | boolean ||的右操作数中的number | boolean 运算符, string | number if语句的第一个分支中的string | number ,而if语句的第二个分支中的boolean .

在这个例子中

class C {  
    data: string | string[];  
    getData() {  
        var data = this.data;  
        return typeof data === "string" ? data : data.join(" ");  
    }  
}

该类型data变量是string在第一条件式和string[]在第二条件表达式,和的推断类型getDatastring . 请注意,必须将data属性复制到本地变量,以使类型保护生效.

在这个例子中

class NamedItem {  
    name: string;  
}

function getName(obj: Object) {  
    return obj instanceof NamedItem ? obj.name : "unknown";  
}

obj的类型在第一个条件表达式中缩小为NamedItem ,并且getName函数的推断类型为string .


5 Statements

This chapter describes the static type checking TypeScript provides for JavaScript statements. TypeScript itself does not introduce any new statement constructs, but it does extend the grammar for local declarations to include interface, type alias, and enum declarations.

5.1 Blocks

Blocks are extended to include local interface, type alias, and enum declarations (classes are already included by the ECMAScript 2015 grammar).

  Declaration: ( Modified )
   …
   InterfaceDeclaration
   TypeAliasDeclaration
   EnumDeclaration

Local class, interface, type alias, and enum declarations are block scoped, similar to let and const declarations.

5.2 Variable Statements

Variable statements are extended to include optional type annotations.

  VariableDeclaration: ( Modified )
   SimpleVariableDeclaration
   DestructuringVariableDeclaration

A variable declaration is either a simple variable declaration or a destructuring variable declaration.

5.2.1 Simple Variable Declarations

A simple variable declaration introduces a single named variable and optionally assigns it an initial value.

  SimpleVariableDeclaration:
   BindingIdentifierTypeAnnotationoptInitializeropt

The type T of a variable introduced by a simple variable declaration is determined as follows:

当变量声明同时指定类型注释和初始化程序表达式时,要求初始化程序表达式的类型可分配给类型注释中给定的类型(第3.11.4节 ).

允许在同一声明空间中针对同一变量名称进行多个声明,前提是每个声明将同一类型与变量关联.

当变量声明具有类型注释时,使用typeof运算符引用要声明的变量对该类型注释是错误的.

以下是一些简单的变量声明及其关联类型的示例.

var a;                          // any  
var b: number;                  // number  
var c = 1;                      // number  
var d = { x: 1, y: "hello" };   // { x: number; y: string; }  
var e: any = "test";            // any

允许执行以下操作,因为单个变量'x'的所有声明将相同的类型(Number)与'x'关联.

var x = 1;  
var x: number;  
if (x == 1) {  
    var x = 2;  
}

在下面的示例中,所有五个变量都属于同一类型,'{x:number; y:数字; }'.

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

var a = { x: 0, y: <number> undefined };  
var b: Point = { x: 0, y: undefined };  
var c = <Point> { x: 0, y: undefined };  
var d: { x: number; y: number; } = { x: 0, y: undefined };  
var e = <{ x: number; y: number; }> { x: 0, y: undefined };

5.2.2 Destructuring Variable Declarations

A destructuring variable declaration introduces zero or more named variables and initializes them with values extracted from properties of an object or elements of an array.

  DestructuringVariableDeclaration:
   BindingPatternTypeAnnotationoptInitializer

每个指定标识符的绑定属性或元素都通过该名称引入一个变量. 变量的类型是与绑定属性或元素关联的类型的扩展形式(第 3.12 ),如下所示.

TODO:将迭代器分解为数组的文档.

与解构变量声明关联的类型T如下确定:

  • 如果声明包含类型注释,则T为该类型.
  • 否则,如果声明包含初始化程序表达式,则T是该初始化程序表达式的类型.
  • 否则, T为Any类型.

The type T associated with a binding property is determined as follows:

  • S为与立即包含的解构变量声明,绑定属性或绑定元素关联的类型.
  • 如果S是Any类型:
    • 如果绑定属性指定了初始化程序表达式,则T是该初始化程序表达式的类型.
    • 否则, T为Any类型.
  • P为绑定属性中指定的属性名称.
  • 如果S具有名称为P的外观属性,则T是该属性的类型.
  • 否则,如果S具有数字索引签名,而P是数字名称,则T是数字索引签名的类型.
  • 否则,如果S具有字符串索引签名,则T是字符串索引签名的类型.
  • 否则,没有任何类型与绑定属性相关联,并且会发生错误.

与绑定元素关联的类型T的确定如下:

  • S为与立即包含的解构变量声明,绑定属性或绑定元素关联的类型.
  • 如果S是Any类型:
    • 如果绑定元素指定一个初始化程序表达式,则T是该初始化程序表达式的类型.
    • 否则, T为Any类型.
  • 如果S不是类似数组的类型(第3.3.2节),则没有类型与绑定属性相关联,并且会发生错误.
  • 如果绑定元素是rest元素,则T是元素类型为E的数组类型,其中ES的数字索引签名的类型.
  • 否则,如果S是类似元组的类型(第3.3.3节):
    • N为数组绑定模式中绑定元素的从零开始的索引.
    • 如果S具有数字名称N的属性,则T是该属性的类型.
    • 否则,没有任何类型与绑定元素相关联,并且会发生错误.
  • 否则,如果S具有数字索引签名,则T是数字索引签名的类型.
  • 否则,没有任何类型与绑定元素相关联,并且会发生错误.

当解构变量声明,绑定属性或绑定元素指定了初始化程序表达式时,要求将初始化程序表达式的类型分配给与解构变量声明,绑定属性或绑定元素相关联的类型的扩展形式.

待办事项:更新规则以反映对使用文字初始值设定项的解构检查的改进.

当输出目标是ECMAScript 2015或更高版本时,除了删除可选的类型注释外,释放的JavaScript代码中的解构变量声明将保持不变.

当输出目标为ECMAScript 3或5时,解构变量声明将重写为简单变量声明. 例如,对象解构声明的形式

var { x, p: y, q: z = false } = getSomeObject();

被重写为简单的变量声明

var _a = getSomeObject(),  
    x = _a.x,  
    y = _a.p,  
    _b = _a.q,  
    z = _b === void 0 ? false : _b;

存在'_a'和'_b'临时变量以确保只对分配的表达式求值一次,而表达式'void 0'仅表示JavaScript值'undefined'.

同样,数组解构声明的形式

var [x, y, z = 10] = getSomeArray();

被重写为简单的变量声明

var _a = getSomeArray(),  
    x = _a[0],  
    y = _a[1],  
    _b = _a[2],  
    z = _b === void 0 ? 10 : _b;

结合两种形式的解构,例如

var { x, p: [y, z = 10] = getSomeArray() } = getSomeObject();

被重写为

var _a = getSomeObject(),  
    x = _a.x,  
    _b = _a.p,  
    _c = _b === void 0 ? getSomeArray() : _b,  
    y = _c[0],  
    _d = _c[1],  
    z = _d === void 0 ? 10 : _d;

5.2.3 Implied Type

A variable, parameter, binding property, or binding element declaration that specifies a binding pattern has an implied type which is determined as follows:

  • If the declaration specifies an object binding pattern, the implied type is an object type with a set of properties corresponding to the specified binding property declarations. The type of each property is the type implied by its binding property declaration, and a property is optional when its binding property declaration specifies an initializer expression.
  • If the declaration specifies an array binding pattern without a rest element, the implied type is a tuple type with elements corresponding to the specified binding element declarations. The type of each element is the type implied by its binding element declaration.
  • If the declaration specifies an array binding pattern with a rest element, the implied type is an array type with an element type of Any.

The implied type of a binding property or binding element declaration is

  • the type of the declaration's initializer expression, if any, or otherwise
  • the implied type of the binding pattern specified in the declaration, if any, or otherwise
  • the type Any.

In the example

function f({ a, b = "hello", c = 1 }) { ... }

the implied type of the binding pattern in the function's parameter is '{ a: any; b?: string; c?: number; }'. Since the parameter has no type annotation, this becomes the type of the parameter.

In the example

var [a, b, c] = [1, "hello", true];

the array literal initializer expression is contextually typed by the implied type of the binding pattern, specifically the tuple type '[any, any, any]'. Because the contextual type is a tuple type, the resulting type of the array literal is the tuple type '[number, string, boolean]', and the destructuring declaration thus gives the types number, string, and boolean to a, b, and c respectively.

5.3 Let and Const Declarations

Let and const declarations are extended to include optional type annotations.

  LexicalBinding: ( Modified )
   SimpleLexicalBinding
   DestructuringLexicalBinding

  SimpleLexicalBinding:
   BindingIdentifierTypeAnnotationoptInitializeropt

  DestructuringLexicalBinding:
   BindingPatternTypeAnnotationoptInitializeropt

TODO: Document scoping and types of let and const declarations.

5.4 If, Do, and While Statements

Expressions controlling 'if', 'do', and 'while' statements can be of any type (and not just type Boolean).

5.5 For Statements

Variable declarations in 'for' statements are extended in the same manner as variable declarations in variable statements (section 5.2).

5.6 For-In Statements

In a 'for-in' statement of the form

for (v in expr) statement

v must be an expression classified as a reference of type Any or the String primitive type, and expr must be an expression of type Any, an object type, or a type parameter type.

In a 'for-in' statement of the form

for (var v in expr) statement

v must be a variable declaration without a type annotation that declares a variable of type Any, and expr must be an expression of type Any, an object type, or a type parameter type.

5.7 For-Of Statements

TODO: Document for-of statements.

5.8 Continue Statements

A 'continue' statement is required to be nested, directly or indirectly (but not crossing function boundaries), within an iteration ('do', 'while', 'for', or 'for-in') statement. When a 'continue' statement includes a target label, that target label must appear in the label set of an enclosing (but not crossing function boundaries) iteration statement.

5.9 Break Statements

A 'break' statement is required to be nested, directly or indirectly (but not crossing function boundaries), within an iteration ('do', 'while', 'for', or 'for-in') or 'switch' statement. When a 'break' statement includes a target label, that target label must appear in the label set of an enclosing (but not crossing function boundaries) statement.

5.10 Return Statements

It is an error for a 'return' statement to occur outside a function body. Specifically, 'return' statements are not permitted at the global level or in namespace bodies.

A 'return' statement without an expression returns the value 'undefined' and is permitted in the body of any function, regardless of the return type of the function.

当'return'语句包含表达式时,如果包含函数包含返回类型注释,则该返回表达式由该返回类型在上下文中键入(第 4.23 ),并且必须具有可分配给该返回类型的类型. 否则,如果包含函数的上下文类型为T ,则Expr上下文类型为T的返回类型.

在没有返回类型注释的函数实现中,返回类型是从函数主体中的" return"语句推断出来的,如第6.3节所述.

在这个例子中

function f(): (x: string) => number {  
    return s => s.length;  
}

" return"语句中的箭头表达式在上下文中由" f"的返回类型键入,因此将" string"类型赋予" s".

5.11 With Statements

与ECMAScript 5的严格模式一样,在TypeScript中使用'with'语句是错误的. 此外,在'with'语句的主体内,TypeScript认为表达式(第 4.3 )中出现的每个标识符均为Any类型,无论其声明的类型如何. 因为" with"语句将静态未知的标识符集放在静态已知的标识符之前,所以不可能为任何标识符有意义地分配静态类型.

5.12 Switch Statements

在'switch'语句中,每个'case'表达式必须具有可分配给 'switch'表达式的类型或从中分配的类型(第 3.11.4节 ).

5.13 Throw Statements

The expression specified in a 'throw' statement can be of any type.

5.14 Try Statements

The variable introduced by a 'catch' clause of a 'try' statement is always of type Any. It is not possible to include a type annotation in a 'catch' clause.


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 are extended to permit the function body to be omitted in overload declarations.

  FunctionDeclaration: ( Modified )
   functionBindingIdentifieroptCallSignature{FunctionBody}
   functionBindingIdentifieroptCallSignature;

A FunctionDeclaration introduces a named value of a function type in the containing declaration space. The BindingIdentifier is optional only when the function declaration occurs in an export default declaration (section 11.3.4.2).

指定主体的函数声明称为函数实现 ,而没有主体的函数声明称为函数重载 . 可以为同一个函数指定多个重载(即,为同一个声明空间中的同一个名称),但是一个函数最多可以有一个实现. 同一函数的所有声明必须指定相同的修饰符集(即, declareexportdefault的相同组合).

当函数具有重载声明时,重载将确定给函数对象提供的类型的调用签名,并且函数实现签名(如果有)必须可分配给该类型. 否则,函数实现本身将确定调用签名.

当一个函数同时具有重载和实现时,重载必须在实现之前,并且所有声明必须是连续的且没有中间的语法元素.

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

函数重载纯粹是编译时构造. 它们对发出的JavaScript没有影响,因此没有运行时成本.

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.

以下是带有重载的函数的示例.

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

在这个例子中

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类型或包含Void或Any类型作为组成部分的并集类型,必须在其主体中的某处至少具有一个return语句. 此规则的例外情况是,函数实现是否包含单个" throw"语句.

函数实现中" this"的类型是Any类型.

在函数实现的签名中,可以通过在参数后面加上初始化程序来将其标记为可选参数. 当参数声明同时包含类型注释和初始值设定项时,初始值设定项表达式将通过声明的类型进行上下文类型化(第4.23节),并且必须可分配给声明的类型,否则会发生编译时错误. 当参数声明没有类型注释但包含初始化程序时,参数的类型是初始化程序表达式的类型的扩展形式(第3.12节).

初始化程序表达式在函数体的范围内进行评估,但不允许引用局部变量,并且仅允许访问在其初始化的参数左侧声明的参数,除非参数引用出现在嵌套函数表达式中.

当输出目标为ECMAScript 3或5时,对于每个带有初始化程序的参数,所生成的JavaScript中将包含一条语句,该语句将默认值替换为省略的参数,如6.6节所述. 这个例子

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

生成与

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

在这个例子中

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

局部变量" x"在参数初始值设定项的范围内(因此隐藏了外部" x"),但是引用它是错误的,因为在评估参数初始值设定项时它将始终未初始化.

6.4 Destructuring Parameter Declarations

参数声明可以指定绑定模式(第 3.9.2.2 ),然后称为解构参数声明 . 与解构变量声明(第5.2.2节)类似,解构参数声明会引入零个或多个命名的局部变量,并使用从对象或数组的属性或元素中提取的值(作为参数的参数)对其进行初始化.

以与通过解构变量声明引入的局部相同的方式确定在解构参数声明中引入的局部类型,除了与解构参数声明关联的类型T的确定如下:

  • 如果声明包含类型注释,则T为该类型.
  • 如果声明出现在具有上下文签名可用的函数表达式中(第4.10节),则T是从上下文签名获得的类型.
  • 否则,如果声明包含初始化程序表达式,则T是初始化程序表达式类型的扩展形式(第3.12节).
  • 否则,如果声明指定了绑定模式,则T是该绑定模式的隐含类型(第5.2.3节).
  • 否则,如果参数是rest参数,则Tany[] .
  • Otherwise, T is any.

当输出目标是ECMAScript 2015或更高版本时,除了删除可选的类型注释之外,在发出的JavaScript代码中,解构参数声明将保持不变. 当输出目标为ECMAScript 3或5时,解构参数声明将重写为局部变量声明.

这个例子

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

声明一个函数drawText ,该函数采用单个类型的参数

{ 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 Generic Functions

函数实现可以在其签名中包含类型参数(第 3.9.2.1 ),然后称为泛型函数 . 类型参数提供了一种机制,用于表达调用操作中参数与返回类型之间的关系. 类型参数没有运行时表示形式,它们纯粹是编译时构造.

在函数实现的签名中声明的类型参数在该函数实现的签名和主体中.

以下是通用函数的示例:

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"参数是约束"可比较"的子类型,因此具有" compareTo"成员. 这将在3.6.1节中进一步描述.

可以在调用操作中显式指定对通用函数的调用的类型参数,或者在可能的情况下,可以从调用中的常规参数的类型推断出类型参数(第4.15.2节). 在这个例子中

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

因为两个参数都是字符串,所以"比较"的类型参数会自动推断为String类型.

6.6 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 (<Parameter> === void 0) { <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.

6.7 Generator Functions

TODO: Document generator functions.

6.8 Asynchronous Functions

TODO: Document asynchronous functions.

6.9 Type Guard Functions

TODO: Document 类型防护函数 ,包括此类型谓词.


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.11.2).

类声明可以在自己的Implements子句中引用接口,以验证它们是否提供了接口的实现.

7.1 Interface Declarations

An interface declaration declares an interface type.

  InterfaceDeclaration:
   interfaceBindingIdentifierTypeParametersoptInterfaceExtendsClauseoptObjectType

  InterfaceExtendsClause:
   extendsClassOrInterfaceTypeList

  ClassOrInterfaceTypeList:
   ClassOrInterfaceType
   ClassOrInterfaceTypeList,ClassOrInterfaceType

  ClassOrInterfaceType:
   TypeReference

InterfaceDeclaration在包含的声明空间中引入了命名类型(第 3.7 ). 接口声明的BindingIdentifier可能不是预定义的类型名称之一(第3.8.1节).

接口可以选择具有类型参数(第3.6.1节),这些类型参数用作在类型引用中引用接口时要提供的实际类型的占位符. 具有类型参数的接口称为通用接口 . 通用接口声明的类型参数在整个声明的范围内,并且可以在InterfaceExtendsClauseObjectType主体中引用.

接口可以从InterfaceExtendsClause中指定的零个或多个基本类型继承. 基本类型必须是对类或接口类型的类型引用.

接口具有在其声明的ObjectType中指定的成员,并且还继承了接口中的声明未隐藏的所有基本类型成员:

  • 属性声明隐藏具有相同名称的公共基本类型属性.
  • 字符串索引签名声明隐藏了基本类型的字符串索引签名.
  • 数字索引签名声明隐藏了基本类型的数字索引签名.

接口声明必须满足以下约束,否则会发生编译时错误:

  • 接口声明不能直接或间接指定源自同一声明的基本类型. 换句话说,无论类型参数如何,接口都不能直接或间接成为其自身的基本类型.
  • 接口不能声明与继承的私有或受保护属性同名的属性.
  • 具有相同名称的继承属性必须相同(第3.11.2节 ).
  • 接口的所有属性必须满足3.9.4节中指定的接口索引签名所隐含的约束.
  • 声明的接口的this-type(第3.6.3节)必须可分配(第3.11.4节 )给每个基本类型引用.

允许接口从多个基本类型继承相同的成员,并且在这种情况下,每个特定成员仅包含一个实例.

以下是两个包含名称相同但类型不同的属性的接口的示例:

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

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

扩展" Mover"和" Shaker"的接口必须声明一个新的" getStatus"属性,否则它将继承两个具有不同类型的" getStatus"属性. 必须声明新的'getStatus'属性,以使生成的'MoverShaker'是'Mover'和'Shaker'的子类型:

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

由于函数和构造函数类型只是包含调用和构造签名的对象类型,因此可以使用接口来声明命名的函数和构造函数类型. 例如:

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

接口是"开放式的",并且相对于公共根目录具有相同限定名称的接口声明(如第 2.3 节中所定义 )构成单个接口.

当通用接口具有多个声明时,所有声明必须具有相同的类型参数列表,即具有相同约束且顺序相同的相同类型参数名称.

在具有多个声明的接口中, extends子句将合并为一组基本类型,而接口声明的主体将合并为单个对象类型. 声明合并产生声明的顺序对应于预先计算每个接口声明的成员,在顺序的成员被写入,到成员的组合列表的接口声明的顺序. 因此,在最后一个接口声明中声明的成员将按照合并类型的声明顺序首先出现.

例如,按此顺序的一系列声明:

interface Document {  
    createElement(tagName: any): Element;  
}

interface Document {  
    createElement(tagName: string): HTMLElement;  
}

interface Document {  
    createElement(tagName: "div"): HTMLDivElement;   
    createElement(tagName: "span"): HTMLSpanElement;  
    createElement(tagName: "canvas"): HTMLCanvasElement;  
}

等效于以下单个声明:

interface Document {  
    createElement(tagName: "div"): HTMLDivElement;   
    createElement(tagName: "span"): HTMLSpanElement;  
    createElement(tagName: "canvas"): HTMLCanvasElement;  
    createElement(tagName: string): HTMLElement;  
    createElement(tagName: any): Element;  
}

请注意,最后一个接口声明的成员首先出现在合并的声明中. 还请注意,保留了在同一接口主体中声明的成员的相对顺序.

TODO:文档类和接口声明合并.

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 and protected members of a base class. When a class containing private or protected 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.11).

在"控件"类中,可以通过" SelectableControl"的实例访问"状态"私有成员. 实际上," SelectableControl"的作用类似于已知具有" select"方法的" Control". "按钮"和"文本框"类是" SelectableControl"的子类型(因为它们都继承自"控件"并且具有"选择"方法),但是"图像"和"位置"类却不是.

7.4 Dynamic Type Checks

TypeScript没有提供用于动态测试对象是否实现特定接口的直接机制. 相反,TypeScript代码可以使用JavaScript技术检查对象上是否存在适当的成员集. 例如,给定第 7.1 节中的声明 ,以下内容是对'MoverShaker'接口的动态检查:

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

如果经常使用这种检查,则可以将其抽象为一个函数:

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

8 Classes

TypeScript extends JavaScript classes to include type parameters, implements clauses, accessibility modifiers, member variable declarations, and parameter property declarations in constructors.

TODO: Document abstract classes.

8.1 Class Declarations

A class declaration declares a class type and a constructor function.

  ClassDeclaration: ( Modified )
   classBindingIdentifieroptTypeParametersoptClassHeritage{ClassBody}

A ClassDeclaration introduces a named type (the class type) and a named value (the constructor function) in the containing declaration space. The class type is formed from the instance members declared in the class body and the instance members inherited from the base class. The constructor function is given an anonymous type formed 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.

类声明的BindingIdentifier可能不是预定义的类型名称之一(第 3.8.1 ). 仅当类声明出现在导出默认声明中时, BindingIdentifier才是可选的(第11.3.4.2节).

类可以选择具有类型参数(第3.6.1节),这些类型参数用作在类型引用中引用该类时要提供的实际类型的占位符. 具有类型参数的类称为泛型类 . 通用类声明的类型参数在整个声明的范围内,并且可以在ClassHeritageClassBody中引用 .

下面的示例在包含的声明空间中引入了一个名为'Point'的命名类型(类类型)和一个名为'Point'的命名值(构造函数).

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

命名类型'Point'完全等同于

interface Point {  
    x: number;  
    y: number;  
    length(): number;  
}

命名值" Point"是一个构造函数,其类型与声明对应

var Point: {  
    new(x: number, y: number): Point;  
    origin: Point;  
};

引用类的上下文区分了类类型和构造函数. 例如,在赋值语句中

var p: Point = new Point(10, 20);

类型注释中的标识符" Point"是指类类型,而new表达式中的标识符" Point"是指构造函数对象.

8.1.1 Class Heritage Specification

TODO: Update this section to reflect expressions in class extends clauses.

类的继承规范由可选的extendsimplements子句组成. extends子句指定该类的基类,而implements子句指定一组用于验证该类为其提供实现的接口.

  ClassHeritage: (修改)
   ClassExtendsClauseoptImplementsClauseopt

  ClassExtendsClause:
   extendsClassType

  ClassType:
   TypeReference

  ImplementsClause:
   implementsClassOrInterfaceTypeList

包含extends子句的称为派生类 ,而extends子句中指定的类称为派生类类. 当类继承规范忽略extends子句时,该类没有基类. 但是,与每种对象类型一样,对该类的类型引用(第3.3.1节)将看起来具有名为" Object"的全局接口类型的成员,除非这些成员被名称相同的成员隐藏.类.

类继承规范必须满足以下约束,否则会发生编译时错误:

  • 如果存在,则extends子句中指定的类型引用必须表示一个类类型. 此外,当作为表达式求值时,类型引用的TypeName部分必须是对类构造函数的引用.
  • 类声明不能直接或间接指定源自同一声明的基类. 换句话说,无论类型参数如何,类都不能直接或间接地成为其自身的基类.
  • 声明的类的this-type(第3.6.3节)必须可分配(第3.11.4节 )给基本类型引用以及implements子句中列出的每个类型引用.
  • 由类声明创建的构造函数类型必须可分配给基类构造函数类型,而忽略构造签名.

The following example illustrates a situation in which the first rule above would be violated:

class A { a: number; }

namespace Foo {  
    var A = 1;  
    class B extends A { b: string; }  
}

当作为表达式求值时, extends子句中的类型引用" A"不引用" A"的类构造函数(而是引用局部变量" A").

唯一违反上述最后两个约束的情况是,当一个类使用不兼容的新成员覆盖一个或多个基类成员时.

请注意,由于TypeScript具有结构化的类型系统,因此类无需显式声明其已实现接口-它足以使该类仅包含适当的实例成员集. 类的implements子句提供一种机制来断言和验证该类是否包含适当的实例成员集,但否则对类类型没有影响.

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.

  ClassElement: ( Modified )
   ConstructorDeclaration
   PropertyMemberDeclaration
   IndexMemberDeclaration

The body of class may optionally contain a single constructor declaration. Constructor declarations are described in section 8.3.

成员声明用于声明类的实例和静态成员. 属性成员声明在8.4节中描述,而索引成员声明在8.5节中描述.

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.

实例成员是类类型(第 8.2.4 )及其相关的this类型的成员. 内构造,实例成员函数,和实例成员访问器,类型this是这种类型的(部分3.6.3类的).

静态成员使用static修饰符声明,并且是构造函数类型的成员(第8.2.5节). 内静态成员函数和静态成员访问器,类型this是构造函数类型.

类类型参数不能在静态成员声明中引用.

8.2.2 Accessibility

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

Public property members can be accessed everywhere without restrictions.

Private property members can be accessed only within their declaring class. Specifically, a private member M declared in a class C can be accessed only within the class body of C.

Protected property members can be accessed only within their declaring class and classes derived from their declaring class, and a protected instance property member must be accessed through an instance of the enclosing class or a subclass thereof. Specifically, a protected member M declared in a class C can be accessed only within the class body of C or the class body of a class derived from C. Furthermore, when a protected instance member M is accessed in a property access E.M within the body of a class D, the type of E is required to be D or a type that directly or indirectly has D as a base type, regardless of type arguments.

Private and protected 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 and protected properties on an object, it is not possible to enforce the private and protected modifiers in dynamic code at run-time. For example, private and protected accessibility can be defeated by changing an object's static type to Any and accessing the member dynamically.

The following example demonstrates private and protected accessibility:

class A {  
    private x: number;  
    protected y: number;  
    static f(a: A, b: B) {  
        a.x = 1;  // Ok  
        b.x = 1;  // Ok  
        a.y = 1;  // Ok  
        b.y = 1;  // Ok  
    }  
}

class B extends A {  
    static f(a: A, b: B) {  
        a.x = 1;  // Error, x only accessible within A  
        b.x = 1;  // Error, x only accessible within A  
        a.y = 1;  // Error, y must be accessed through instance of B  
        b.y = 1;  // Ok  
    }  
}

In class 'A', the accesses to 'x' are permitted because 'x' is declared in 'A', and the accesses to 'y' are permitted because both take place through an instance of 'A' or a type derived from 'A'. In class 'B', access to 'x' is not permitted, and the first access to 'y' is an error because it takes place through an instance of 'A', which is not derived from the enclosing class 'B'.

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. Only public and protected property members can be overridden.

当派生类的属性成员与基类属性成员具有相同的名称和种类(实例或静态)时,可以说派生类中的属性成员将覆盖基类中的属性成员. 覆盖属性成员的类型必须可分配给覆盖属性成员的类型(第 3.11.4节 ),否则会发生编译时错误.

派生类实例成员函数可以覆盖基类实例成员函数,而其他种类的成员则不能.

派生类实例成员变量和访问器可以覆盖基类实例成员变量和访问器,但其他种类的成员则不能.

如上所述,只要类型兼容,基类静态属性成员就可以被任何类型的派生类静态属性成员覆盖.

当派生类索引成员与基类索引成员具有相同的索引类型(字符串或数字)时,可以说派生类中的索引成员将覆盖基类中的索引成员. 覆盖索引成员的类型必须可分配给覆盖索引成员的类型(第3.11.4节 ),否则会发生编译时错误.

8.2.4 Class Types

类声明声明了一个名为类类型的新命名类型(第 3.7 ). 内的类的构造函数和实例成员函数的类型, this是此型(部分3.6.3该类类型). 类类型具有以下成员:

  • 类主体中每个实例成员变量声明的属性.
  • A property of a function type for each instance member function declaration in the class body.
  • 类主体中每个唯一命名的实例成员访问器声明的属性.
  • 使用publicprivateprotected修饰符声明的每个构造函数参数的属性.
  • An index signature for each instance index member declaration in the class body.
  • 所有未在类中覆盖的基类实例属性或索引成员.

类的所有实例属性成员(包括私有或受保护的实例属性成员)必须满足3.9.4节中指定的类的索引成员所隐含的约束.

在这个例子中

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

" A"的类类型等效于

interface A {  
    x: number;  
    f: () => void;  
    g: (a: any) => any;  
}

并且" B"的类类型等效于

interface B {  
    x: number;  
    y: number;  
    f: () => void;  
    g: (b: boolean) => boolean;  
}

请注意,类中的静态声明不会影响类的类型,相反,静态声明会在构造函数对象上引入属性. 还要注意,在" B"中声明" g"会覆盖从" 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 (if any) and returning an instantiation of the class type with those type parameters passed as type arguments.
  • 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 (if any) and returning an instantiation of the class type with those type parameters passed as type arguments.
  • 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 (if any) and returning an instantiation of the class type with those type parameters passed as type arguments.
  • 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 (if any) and returning an instantiation of the class type with those type parameters passed as type arguments.
  • 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', the type of which is an instantiation of the class type with type Any supplied as a type argument for each type parameter.
  • All base class constructor function type properties that are not overridden in the class.

Every class automatically contains a static property member named 'prototype', the type of which is the containing class with type Any substituted for each type parameter.

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 each construct signature in the constructor function types has the same type parameters as its class and returns an instantiation of its class with those type parameters passed as type arguments. 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:
   AccessibilityModifieroptconstructor(ParameterListopt){FunctionBody}
   AccessibilityModifieroptconstructor(ParameterListopt);

Constructor declarations that specify a body are called constructor implementations and constructor declarations without a body are called constructor overloads. It is possible to specify multiple constructor overloads in a class, but a class can have at most one constructor implementation. All constructor declarations in a class must specify the same set of modifiers. Only public constructors are supported and private or protected constructors result in an error.

In a class with no constructor declaration, an automatic constructor is provided, as described in section 8.3.3.

当类具有构造函数重载时,重载确定提供给构造函数对象的类型的构造签名,并且构造函数实现签名(如果有)必须可分配给该类型. 否则,构造函数实现本身将确定构造签名. 这与在函数声明中处理重载的方式完全相同(第6.2节).

当一个类同时具有构造函数重载和构造函数实现时,重载必须在实现之前,并且所有声明都必须是连续的,并且中间没有语法元素.

构造函数的函数体允许包含return语句. 如果return语句指定表达式,则这些表达式必须具有可分配给该类的this-type(第3.6.3节)的类型.

泛型类的类型参数在范围内,可以在构造函数声明中访问.

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. When the output target is ECMAScript 3 or 5, 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, private, or protected 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  
    }  
}

A parameter property declaration may declare an optional parameter (by including a question mark or a default value), but the property introduced by such a declaration is always considered a required property (section 3.3.6).

8.3.2 Super Calls

超级调用(第 4.9.1 )用于调用基类的构造函数. 超级调用由关键字super组成,后跟括号中的参数列表. 例如:

class ColoredPoint extends Point {  
    constructor(x: number, y: number, public color: string) {  
        super(x, y);  
    }  
}

没有extends子句的类的构造函数不能包含超级调用,而派生类的构造函数必须在其函数体内的某个位置至少包含一个超级调用. 不允许在构造函数外部或构造函数内部的局部函数中进行超级调用.

如果满足以下两个条件,则构造函数主体中的第一条语句必须是超级调用:

  • The containing class is a derived class.
  • 构造函数声明参数属性,或者包含类声明带有初始化程序的实例成员变量.

在这种必需的超级调用中,参数表达式引用this导致编译时错误.

如果该类没有基类,则使用构造函数初始化参数属性和实例成员变量的操作将立即在构造函数主体的开头进行;如果该类是派生类,则在超级调用之后立即进行初始化.

8.3.3 Automatic Constructors

If a class omits a constructor declaration, an automatic constructor is provided.

在没有extends子句的类中,自动构造函数没有参数,除了执行实例成员变量初始化器(第 8.4.1 )(如果有)之外,不执行任何操作.

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

然后执行实例成员变量初始化器(如果有).

8.4 Property Member Declarations

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

  PropertyMemberDeclaration:
   MemberVariableDeclaration
   MemberFunctionDeclaration
   MemberAccessorDeclaration

没有static修饰符的成员声明称为实例成员声明. 实例属性成员声明以类类型声明属性(第 8.2.4 ),并且必须指定包含类中所有实例属性成员和参数属性声明中唯一的名称,但实例get和set访问器声明可以成对出现指定相同的名称.

具有static修饰符的成员声明称为静态成员声明. 静态属性成员声明以构造函数类型(第8.2.5节)声明属性,并且必须指定包含类中所有静态属性成员声明中唯一的名称,但静态get和set访问器声明可以成对指定.一样的名字.

请注意,实例成员和静态属性成员的声明空间是分开的. 因此,可以使实例成员和静态属性成员具有相同的名称.

除覆盖之外,如第8.2.3节中所述,派生类声明与基类成员具有相同名称和种类(实例或静态)的属性成员是错误的.

每个类都会自动包含一个名为" prototype"的静态属性成员,该成员的类型是具有类型Any的类类型的实例化,作为每个类型参数的类型实参. 显式声明名称为" prototype"的静态属性成员是错误的.

下面是同时包含实例和静态属性成员声明的类的示例:

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

类类型" Point"具有以下成员:

interface Point {  
    x: number;  
    y: number;  
    distance(p: Point);  
}

构造函数" Point"具有与声明相对应的类型:

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:
   AccessibilityModifieroptstaticoptPropertyNameTypeAnnotationoptInitializeropt;

The type associated with a member variable declaration is determined in the same manner as an ordinary variable declaration (see section 5.2).

实例成员变量声明在类类型中引入成员,并可以选择在类的实例上初始化属性. 在实例成员变量声明中的初始化一次班级的每一个新的实例执行和相当于分配到的性能this在构造函数中. 在实例成员变量的初始化表达式中, this是类的this-type(第3.6.3节).

静态成员变量声明在构造函数类型中引入属性,并可以选择在构造函数对象上初始化属性. 加载包含的脚本或模块时,静态成员变量声明中的初始化程序将执行一次.

实例成员变量的初始化器表达式在类构造函数主体的范围内求值,但不允许引用构造函数的参数或局部变量. 这实际上意味着来自外部作用域的与构造函数参数或局部变量同名的实体在实例成员变量的初始化表达式中不可访问.

由于实例成员变量初始化器等效于构造函数中this属性的分配,因此该示例

class Employee {  
    public name: string;  
    public address: string;  
    public retired = false;  
    public manager: Employee = null;  
    public reports: Employee[] = [];  
}

相当于

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:
   AccessibilityModifieroptstaticoptPropertyNameCallSignature{FunctionBody}
   AccessibilityModifieroptstaticoptPropertyNameCallSignature;

成员函数声明被以相同的方式处理为一个普通的函数声明(第 6 ),不同之处在于在一个成员函数this具有已知的类型.

同一成员函数的所有声明必须指定相同的可访问性(公共,私有或受保护)和种类(实例或静态).

实例成员函数声明以类类型声明一个属性,并将函数对象分配给该类的原型对象上的属性. 在实例成员函数声明的主体中, this是类的this-type(第3.6.3节).

静态成员函数声明以构造函数的类型声明属性,并将函数对象分配给构造函数对象的属性. 在静态成员函数声明体的类型, this是构造函数类型.

成员函数可以使用超级属性访问来访问重写的基类成员(第4.9.2节). 例如

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

在静态成员函数中, this表示在其上调用了静态成员函数的构造函数对象. 因此,对" new this()"的调用实际上可能会调用派生的类构造函数:

class A {  
    a = 1;  
    static create() {  
        return new this();  
    }  
}

class B extends A {  
    b = 2;  
}

var x = A.create();  // new A()  
var y = B.create();  // new B()

请注意,TypeScript不需要或验证派生的构造函数是基本构造函数的子类型. 换句话说,将" B"的声明更改为

class B extends A {  
    constructor(public b: number) {  
        super();  
    }  
}

即使从'create'函数调用构造函数时未指定参数(因此将值'undefined'赋予'b')也不会在示例中引起错误.

8.4.3 Member Accessor Declarations

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

  MemberAccessorDeclaration:
   AccessibilityModifieroptstaticoptGetAccessor
   AccessibilityModifieroptstaticoptSetAccessor

获取和设置访问器的处理方式与对象文字(第 4.5 中的处理方式相同 ,只是上下文类型在成员访问器声明中永远不可用.

具有相同成员名称的访问者必须指定相同的可访问性.

实例成员访问器声明以类类型声明一个属性,并使用get或set访问器在该类的原型对象上定义一个属性. 在一个实例成员访问器声明的主体中, this是此型(部分的3.6.3类的).

静态成员访问器声明在构造函数类型中声明一个属性,并在具有get或set访问器的类的构造函数对象上定义一个属性. 在静态成员访问器声明体的类型, this是构造函数类型.

如第8.7.1节所述,在生成的JavaScript中,Get和set访问器作为对'Object.defineProperty'的调用而发出.

8.4.4 Dynamic Property Declarations

如果属性成员声明的PropertyName是不表示众所周知的符号( 2.2.3的计算的属性名称,则该构造被视为动态属性声明 . 以下规则适用于动态属性声明:

  • 动态属性声明不会在类类型或构造函数类型中引入属性.
  • 动态属性分配的属性名称表达式必须是Any类型或String,Number或Symbol原语类型.
  • 如果属性名称表达式的类型为Any或Number原语类型,则与动态属性声明关联的名称被视为数字属性名称.

8.5 Index Member Declarations

索引成员声明在类类型中引入了索引签名(第 3.9.4 ).

  IndexMemberDeclaration:
   IndexSignature;

索引成员声明没有主体,并且不能指定可访问性修饰符.

一个类声明最多可以包含一个字符串索引成员声明和一个数字索引成员声明. 类的所有实例属性成员必须满足3.9.4节中指定的类的索引成员所隐含的约束.

不能为类的静态端声明索引成员.

请注意,在类中包括字符串索引签名几乎没有意义,因为它约束了该类的所有实例属性. 但是,当以类似数组的方式使用类时,数字索引签名对于控制元素类型很有用.

8.6 Decorators

TODO: Document decorators.

8.7 Code Generation

When the output target is ECMAScript 2015 or higher, type parameters, implements clauses, accessibility modifiers, and member variable declarations are removed in the emitted code, but otherwise class declarations are emitted as written. When the output target is ECMAScript 3 or 5, more comprehensive rewrites are performed, as described in this section.

8.7.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.6.

ParameterPropertyAssignments是一系列分配,对于构造函数中的每个参数属性声明,按照声明的顺序依次分配一个

this.<ParameterName> = <ParameterName>;

其中ParameterName是参数属性的名称.

MemberVariableAssignments是一系列分配,对于每个实例成员变量声明,使用初始化程序(按声明的顺序)分别为以下形式:

this.<MemberName> = <InitializerExpression>;

其中MemberName是成员变量的名称, InitializerExpression是为初始化程序表达式生成的代码.

ConstructorStatements是为构造函数主体中指定的语句生成的代码.

MemberFunctionStatements是一组语句序列,每个成员函数声明或成员访问器声明均按声明顺序进行.

实例成员函数声明生成以下形式的语句

<ClassName>.prototype.<MemberName> = function (<FunctionParameters>) {  
    <DefaultValueAssignments>  
    <FunctionStatements>  
}

和静态成员函数声明生成以下形式的语句

<ClassName>.<MemberName> = function (<FunctionParameters>) {  
    <DefaultValueAssignments>  
    <FunctionStatements>  
}

其中MemberName是成员函数的名称, FunctionParametersDefaultValueAssignmentsFunctionStatements对应于为常规函数声明生成的那些函数,如6.6节所述.

一个get或set实例成员访问器声明,或一对具有相同名称的get和set实例成员访问器声明,将生成以下形式的语句

Object.defineProperty(<ClassName>.prototype, "<MemberName>", {  
    get: function () {  
        <GetAccessorStatements>  
    },  
    set: function (<ParameterName>) {  
        <SetAccessorStatements>  
    },  
    enumerable: true,  
    configurable: true  
};

一个get或set静态成员访问器声明,或者一对具有相同名称的get和set静态成员访问器声明,生成以下形式的语句

Object.defineProperty(<ClassName>, "<MemberName>", {  
    get: function () {  
        <GetAccessorStatements>  
    },  
    set: function (<ParameterName>) {  
        <SetAccessorStatements>  
    },  
    enumerable: true,  
    configurable: true  
};

其中MemberName是成员访问器的名称, GetAccessorStatements是为get Acessor的函数主体中的语句生成的代码, ParameterName是set访问器参数的名称, SetAccessorStatements是为set访问器的函数主体中的语句生成的代码. 仅当声明了get访问器时才包括'get'属性,而仅当声明了set访问器时才包括'set'属性.

StaticVariableAssignments是一系列语句,对于每个带有初始化程序的静态成员变量声明,每个声明均按声明的顺序进行,形式为

<ClassName>.<MemberName> = <InitializerExpression>;

其中MemberName是静态变量的名称, InitializerExpression是为初始化程序表达式生成的代码.

8.7.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);

否则,如果要求构造函数以超级调用开头(如第 8.3.2 节所述),则存在SuperCallStatement ,其形式为

_super.call(this, <SuperCallArguments>)

其中, SuperCallArguments是超级调用中指定的参数列表. 请注意,此调用在使用初始化程序为参数属性和成员变量生成的代码之前. 构造函数中其他地方的超级调用会生成类似的代码,但是为此类调用生成的代码将成为ConstructorStatements部分的一部分.

构造函数中的超级属性访问,实例成员函数或实例成员访问器生成的JavaScript等效于

_super.prototype.<PropertyName>

其中PropertyName是引用的基类属性的名称. 当超级属性访问出现在函数调用中时,生成的JavaScript等效于

_super.prototype.<PropertyName>.call(this, <Arguments>)

其中Arguments是为函数调用中指定的参数列表生成的代码.

静态成员函数或静态成员访问器中的超级属性访问生成的JavaScript等效于

_super.<PropertyName>

其中PropertyName是引用的基类属性的名称. 当超级属性访问出现在函数调用中时,生成的JavaScript等效于

_super.<PropertyName>.call(this, <Arguments>)

其中Arguments是为函数调用中指定的参数列表生成的代码.


9 Enums

An enum type is a distinct subtype of the Number primitive type with an associated set of named constants that define the possible values of the enum type.

9.1 Enum Declarations

An enum declaration declares an enum type and an enum object.

  EnumDeclaration:
   constoptenumBindingIdentifier{EnumBodyopt}

An EnumDeclaration introduces a named type (the enum type) and a named value (the enum object) in the containing declaration space. The enum type is a distinct subtype of the Number primitive type. The enum object is a value of an anonymous object type containing a set of properties, all of the enum type, corresponding to the values declared for the enum type in the body of the declaration. The enum object's type furthermore includes a numeric index signature with the signature '[x: number]: string'.

The BindingIdentifier of an enum declaration may not be one of the predefined type names (section 3.8.1).

当枚举声明包含const修饰符时,它被称为常量枚举声明. 常量枚举声明的成员必须都具有可以在编译时计算的常量值. 常量枚举声明将在9.4节中讨论.

这个例子

enum Color { Red, Green, Blue }

声明Number原始类型的子类型,称为" Color",并引入变量" Color",其类型与声明相对应

var Color: {  
    [x: number]: string;  
    Red: Color;  
    Green: Color;  
    Blue: Color;  
};

如第9.5节所述,数字索引签名反映了在每个枚举对象中自动生成的"反向映射". 反向映射提供了一种获取枚举值的字符串表示形式的便捷方法. 例如

var c = Color.Red;  
console.log(Color[c]);  // Outputs "Red"

9.2 Enum Members

The body of an enum declaration defines zero or more enum members which are the named values of the enum type. Each enum member has an associated numeric value of the primitive type introduced by the enum declaration.

  EnumBody:
   EnumMemberList,opt

  EnumMemberList:
   EnumMember
   EnumMemberList,EnumMember

  EnumMember:
   PropertyName
   PropertyName = EnumValue

  EnumValue:
   AssignmentExpression

The PropertyName of an enum member cannot be a computed property name (2.2.3).

枚举成员可以是常量成员,也可以是计算成员 . 常量成员具有已知的常量值,该值将替换生成的JavaScript代码中对成员的引用. 计算成员具有在运行时计算的值,而在编译时未知. 不会对引用的计算成员执行替换.

枚举成员的分类如下:

  • 如果成员声明未指定任何值,则该成员被视为常量枚举成员. 如果该成员是枚举声明中的第一个成员,则将其赋值为零. 否则,将其前一个成员的值加1,并且如果前一个成员不是常量枚举成员,则会发生错误.
  • 如果成员声明指定了可以归为常量枚举表达式(如下定义)的值,则该成员被视为常量枚举成员.
  • 否则,该成员被视为计算枚举成员.

枚举值表达式的类型必须为Any,Number基本类型或枚举类型本身.

常量枚举表达式是表达式语法的子集,可以在编译时对其进行完全评估. 如果表达式是以下之一,则将其视为常量枚举表达式:

  • 数字文字.
  • 表示同一常量枚举声明中先前声明的成员的标识符或属性访问.
  • 带括号的常量枚举表达式.
  • +,–或〜一元运算符应用于常量枚举表达式.
  • +,–,*,/,%,<<,>>,>>>,&,^或| 运算符应用于两个常量枚举表达式.

在这个例子中

enum Test {  
    A,  
    B,  
    C = Math.floor(Math.random() * 1000),  
    D = 10,  
    E  
}

" A"," B"," D"和" E"是常数成员,分别具有值0、1、10和11,而" C"是计算成员.

在这个例子中

enum Style {  
    None = 0,  
    Bold = 1,  
    Italic = 2,  
    Underline = 4,  
    Emphasis = Bold | Italic,  
    Hyperlink = Bold | Underline  
}

所有成员都是常任理事国. 注意,枚举成员声明可以无条件引用其他枚举成员. 同样,由于枚举是Number原语类型的子类型,因此可以使用数字运算符(例如按位OR运算符)来计算枚举值.

9.3 Declaration Merging

枚举是"开放式的",并且相对于公共根具有相同限定名称的枚举声明(如第 2.3 节中所定义 )定义单个枚举类型并有助于单个枚举对象.

一个枚举声明不可能继续另一个枚举的自动编号顺序,并且当一个枚举类型具有多个声明时,只允许一个声明为第一个成员省略一个值.

合并枚举声明时,它们必须全部指定const修饰符或全部不指定const修饰符.

9.4 Constant Enum Declarations

An enum declaration that specifies a const modifier is a constant enum declaration. In a constant enum declaration, all members must have constant values and it is an error for a member declaration to specify an expression that isn't classified as a constant enum expression.

Unlike regular enum declarations, constant enum declarations are completely erased in the emitted JavaScript code. For this reason, it is an error to reference a constant enum object in any other context than a property access that selects one of the enum's members. For example:

const enum Comparison {  
    LessThan = -1,  
    EqualTo = 0,  
    GreaterThan = 1  
}

var x = Comparison.EqualTo;  // Ok, replaced with 0 in emitted code  
var y = Comparison[Comparison.EqualTo];  // Error  
var z = Comparison;  // Error

The entire const enum declaration is erased in the emitted JavaScript code. Thus, the only permitted references to the enum object are those that are replaced with an enum member value.

9.5 Code Generation

An enum declaration generates JavaScript equivalent to the following:

var <EnumName>;  
(function (<EnumName>) {  
    <EnumMemberAssignments>  
})(<EnumName>||(<EnumName>={}));

EnumName is the name of the enum.

EnumMemberAssignments is a sequence of assignments, one for each enum member, in order they are declared, of the form

<EnumName>[<EnumName>["<MemberName>"] = <Value>] = "<MemberName>";

where MemberName is the name of the enum member and Value is the assigned constant value or the code generated for the computed value expression.

例如,第 9.1 节中的"颜色"枚举示例生成以下JavaScript:

var Color;  
(function (Color) {  
    Color[Color["Red"] = 0] = "Red";  
    Color[Color["Green"] = 1] = "Green";  
    Color[Color["Blue"] = 2] = "Blue";  
})(Color||(Color={}));

10 Namespaces

命名空间提供了一种在命名容器的层次结构中组织代码和声明的机制. 命名空间具有已命名的成员,每个成员均表示值,类型或名称空间或其某种组合,并且这些成员可以是本地的也可以是导出的. 命名空间的主体对应于一次执行的功能,从而提供了一种机制,用于确保局部状态并确保隔离. 命名空间可以看作是 立即调用的函数表达 (IIFE)模式的形式化 .

10.1 Namespace Declarations

A namespace declaration introduces a name with a namespace meaning and, in the case of an instantiated namespace, a value meaning in the containing declaration space.

  NamespaceDeclaration:
   namespaceIdentifierPath{NamespaceBody}

  IdentifierPath:
   BindingIdentifier
   IdentifierPath.BindingIdentifier

Namespaces are declared using the namespace keyword, but for backward compatibility of earlier versions of TypeScript a module keyword can also be used.

Namespaces are either instantiated or non-instantiated. A non-instantiated namespace is a namespace containing only interface types, type aliases, and other non-instantiated namespace. An instantiated namespace is a namespace that doesn't meet this definition. In intuitive terms, an instantiated namespace is one for which a namespace instance is created, whereas a non-instantiated namespace is one for which no code is generated.

当名称空间标识符被引用为NamespaceName (第 3.8.2 )时,它表示名称空间和类型名称的容器,而当名称空间标识符被引用为PrimaryExpression (第4.3节)时,则表示单例名称空间实例. 例如:

namespace M {  
    export interface P { x: number; y: number; }  
    export var a = 1;  
}

var p: M.P;             // M used as NamespaceName  
var m = M;              // M used as PrimaryExpression  
var x1 = M.a;           // M used as PrimaryExpression  
var x2 = m.a;           // Same as M.a  
var q: m.P;             // Error

上面,当" M"用作PrimaryExpression时 ,表示一个具有单个成员" a"的对象实例,当" M"用作NamespaceName时,它表示一个具有单个类型成员" P"的容器. 该示例的最后一行是一个错误,因为'm'是一个不能在类型名称中引用的变量.

如果上面的'M'声明排除了导出的变量'a',则'M'将是未实例化的名称空间,并且将'M'引用为PrimaryExpression将会是错误的.

指定具有多个标识符的IdentifierPath的名称空间声明等效于一系列嵌套的单标识符名称空间声明,其中除最外层的所有其他名称空间声明都会自动导出. 例如:

namespace A.B.C {  
    export var x = 1;  
}

对应于

namespace A {  
    export namespace B {  
        export namespace C {  
            export var x = 1;  
        }  
    }  
}

由名称空间和命名类型名称形成的层次结构部分地反映了由名称空间实例和成员形成的层次结构. 这个例子

namespace A {  
    export namespace B {  
        export class C { }  
    }  
}

引入了带有限定名称" ABC"的命名类型,还引入了可使用表达式" ABC"访问的构造函数. 因此,在示例中

var c: A.B.C = new A.B.C();

实际上," ABC"的两次出现实际上是指不同的实体. 出现的上下文确定" ABC"是作为类型名称还是表达式进行处理.

10.2 Namespace Body

The body of a namespace corresponds to a function that is executed once to initialize the namespace instance.

  NamespaceBody:
   NamespaceElementsopt

  NamespaceElements:
   NamespaceElement
   NamespaceElementsNamespaceElement

  NamespaceElement:
   Statement
   LexicalDeclaration
   FunctionDeclaration
   GeneratorDeclaration
   ClassDeclaration
   InterfaceDeclaration
   TypeAliasDeclaration
   EnumDeclaration
   NamespaceDeclaration
   AmbientDeclaration
   ImportAliasDeclaration
   ExportNamespaceElement

  ExportNamespaceElement:
   exportVariableStatement
   exportLexicalDeclaration
   exportFunctionDeclaration
   exportGeneratorDeclaration
   exportClassDeclaration
   exportInterfaceDeclaration
   exportTypeAliasDeclaration
   exportEnumDeclaration
   exportNamespaceDeclaration
   exportAmbientDeclaration
   exportImportAliasDeclaration

10.3 Import Alias Declarations

Import alias declarations are used to create local aliases for entities in other namespaces.

  ImportAliasDeclaration:
   importBindingIdentifier=EntityName;

  EntityName:
   NamespaceName
   NamespaceName.IdentifierReference

An EntityName consisting of a single identifier is resolved as a NamespaceName and is thus required to reference a namespace. The resulting local alias references the given namespace and is itself classified as a namespace.

An EntityName consisting of more than one identifier is resolved as a NamespaceName followed by an identifier that names an exported entity in the given namespace. The resulting local alias has all the meanings of the referenced entity. (As many as three distinct meanings are possible for an entity name—value, type, and namespace.) In effect, it is as if the imported entity was declared locally with the local alias name.

In the example

namespace A {  
    export interface X { s: string }  
    export var X: X;  
}

namespace B {  
    interface A { n: number }  
    import Y = A;    // Alias for namespace A  
    import Z = A.X;  // Alias for type and value A.X  
    var v: Z = Z;  
}

within 'B', 'Y' is an alias only for namespace 'A' and not the local interface 'A', whereas 'Z' is an alias for all exported meanings of 'A.X', thus denoting both an interface type and a variable.

If the NamespaceName portion of an EntityName references an instantiated namespace, the NamespaceName is required to reference the namespace instance when evaluated as an expression. In the example

namespace A {  
    export interface X { s: string }  
}

namespace B {  
    var A = 1;  
    import Y = A;  
}

'Y' is a local alias for the non-instantiated namespace 'A'. If the declaration of 'A' is changed such that 'A' becomes an instantiated namespace, for example by including a variable declaration in 'A', the import statement in 'B' above would be an error because the expression 'A' doesn't reference the namespace instance of namespace 'A'.

When an import statement includes an export modifier, all meanings of the local alias are exported.

10.4 Export Declarations

An export declaration declares an externally accessible namespace member. An export declaration is simply a regular declaration prefixed with the keyword export.

名称空间的导出声明空间(第 2.3 )的成员构成名称空间的导出成员集 . 命名空间的实例类型是一种对象类型,其名称空间的导出成员集中的每个成员都有一个表示值的属性.

导出的成员取决于一组(可能为空)命名类型(第3.7节). 这些命名类型必须至少具有与导出成员相同的可访问性,否则会发生错误.

成员所依赖的命名类型是在直接依赖的传递闭包中出现的命名类型,其定义如下:

  • 一种可变直接取决于在其类型注释所指定的类型 .
  • 函数直接取决于参数或返回类型注释中指定的每个Type .
  • 一类直接取决于指定为类型参数约束各类型 ,每个TypeReference指定为基类或实现的接口,并且在构造参数类型注释指定的每个类型 ,公共成员变量类型的注释,公共成员函数参数或返回类型的注释,公共成员访问器参数或返回类型注释或索引签名类型注释.
  • 接口直接取决于指定为类型参数约束,指定为基本接口的每个TypeReference,和指定作为其主体的对象类型的每个类型 .
  • 名称空间直接取决于其导出的成员.
  • TypeObjectType直接取决于在任何嵌套级别的类型中出现的每个TypeReference .
  • TypeReference直接取决于它引用的类型以及指定为类型实参的每个Type .

具有根名称空间R (第2.3节)的命名类型T称为至少与成员M 一样可访问,如果

  • R是全局名称空间或模块,或者
  • RM的父名称空间链中的名称空间.

在这个例子中

interface A { x: string; }

namespace M {  
    export interface B { x: A; }  
    export interface C { x: B; }  
    export function foo(c: C) { … }  
}

" foo"函数取决于命名的类型" A"," B"和" C". 为了导出" foo",还必须导出" B"和" C",否则它们将至少不如" foo"可访问. " A"接口已经至少与" foo"具有相同的可访问性,因为在foo的命名空间的父命名空间中声明了I t.

10.5 Declaration Merging

命名空间是"开放式的",并且相对于公共根(如 2.3 节中所定义具有相同限定名称的命名空间声明构成单个命名空间. 例如,命名空间"外部"的以下两个声明可能位于单独的源文件中.

文件a.ts:

namespace outer {  
    var local = 1;           // Non-exported local variable  
    export var a = local;    // outer.a  
    export namespace inner {  
        export var x = 10;   // outer.inner.x  
    }  
}

文件b.ts:

namespace outer {  
    var local = 2;           // Non-exported local variable  
    export var b = local;    // outer.b  
    export namespace inner {  
        export var y = 20;   // outer.inner.y  
    }  
}

假设这两个源文件是同一程序的一部分,则这两个声明将以全局名称空间作为它们的公共根,因此将对同一名称空间实例有所贡献,其实例类型为:

{  
    a: number;  
    b: number;  
    inner: {  
        x: number;  
        y: number;  
    };  
}

声明合并不适用于由导入别名声明创建的本地别名. 换句话说,不可能在同一名称空间主体中具有相同名称的导入别名声明和名称空间声明.

TODO: Clarify rules for alias resolution.

声明合并还扩展到名称空间声明,具有相对于作为函数,类或枚举声明的公共根的相同限定名称:

  • When merging a function and a namespace, the type of the function object is merged with the instance type of the namespace. In effect, the overloads or implementation of the function provide the call signatures and the exported members of the namespace provide the properties of the combined type.
  • 合并类和名称空间时,构造函数对象的类型将与名称空间的实例类型合并. 实际上,类构造函数的重载或实现提供了构造签名,而类的静态成员和名称空间的导出成员提供了组合类型的属性. 具有相同名称的静态类成员和导出的名称空间成员是错误的.
  • 合并枚举和名称空间时,枚举对象的类型将与名称空间的实例类型合并. 实际上,枚举的成员和名称空间的导出成员提供了组合类型的属性. 枚举成员和导出的名称空间成员具有相同的名称是错误的.

合并非环境函数或类声明和非环境命名空间声明时,该函数或类声明必须位于同一源文件中的命名空间声明之前. 这样可以确保将共享对象实例创建为功能对象. (虽然可以在创建对象后向其添加属性,但是在事实创建后不能使该对象"可调用".)

这个例子

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

function point(x: number, y: number): Point {  
    return { x: x, y: y };  
}

namespace point {  
    export var origin = point(0, 0);  
    export function equals(p1: Point, p2: Point) {  
        return p1.x == p2.x && p1.y == p2.y;  
    }  
}

var p1 = point(0, 0);  
var p2 = point.origin;  
var b = point.equals(p1, p2);

将'point'声明为具有两个属性'origin'和'equals'的函数对象. 请注意," point"的名称空间声明位于函数声明之后.

10.6 Code Generation

A namespace generates JavaScript code that is equivalent to the following:

var <NamespaceName>;  
(function(<NamespaceName>) {  
    <NamespaceStatements>  
})(<NamespaceName>||(<NamespaceName>={}));

where NamespaceName is the name of the namespace and NamespaceStatements is the code generated for the statements in the namespace body. The NamespaceName function parameter may be prefixed with one or more underscore characters to ensure the name is unique within the function body. Note that the entire namespace is emitted as an anonymous function that is immediately executed. This ensures that local variables are in their own lexical environment isolated from the surrounding context. Also note that the generated function doesn't create and return a namespace instance, but rather it extends the existing instance (which may have just been created in the function call). This ensures that namespaces can extend each other.

An import statement generates code of the form

var <Alias> = <EntityName>;

This code is emitted only if the imported entity is referenced as a PrimaryExpression somewhere in the body of the importing namespace. If an imported entity is referenced only as a TypeName or NamespaceName, nothing is emitted. This ensures that types declared in one namespace can be referenced through an import alias in another namespace with no run-time overhead.

When a variable is exported, all references to the variable in the body of the namespace are replaced with

<NamespaceName>.<VariableName>

This effectively promotes the variable to be a property on the namespace instance and ensures that all references to the variable become references to the property.

When a function, class, enum, or namespace is exported, the code generated for the entity is followed by an assignment statement of the form

<NamespaceName>.<EntityName> = <EntityName>;

This copies a reference to the entity into a property on the namespace instance.


11 Scripts and Modules

TypeScript implements support for ECMAScript 2015 modules and supports down-level code generation targeting CommonJS, AMD, and other module systems.

11.1 Programs and Source Files

A TypeScript program consists of one or more source files.

  SourceFile:
   ImplementationSourceFile
   DeclarationSourceFile

  ImplementationSourceFile:
   ImplementationScript
   ImplementationModule

  DeclarationSourceFile:
   DeclarationScript
   DeclarationModule

Source files with extension '.ts' are implementation source files containing statements and declarations, and source files with extension '.d.ts' are declaration source files containing declarations only.

Declaration source files are a strict subset of implementation source files and are used to declare the static type information associated with existing JavaScript code in an adjunct manner. They are entirely optional but enable the TypeScript compiler and tools to provide better verification and assistance when integrating existing JavaScript code and libraries in a TypeScript application.

When a TypeScript program is compiled, all of the program's source files are processed together. Statements and declarations in different source files can depend on each other, possibly in a circular fashion. By default, a JavaScript output file is generated for each implementation source file in a compilation, but no output is generated from declaration source files.

11.1.1 Source Files Dependencies

The TypeScript compiler automatically determines a source file's dependencies and includes those dependencies in the program being compiled. The determination is made from "reference comments" and module import declarations as follows:

依次将包含为依赖项的任何文件以引用方式分析其引用,直到确定所有依赖项为止.

11.2 Scripts

Source files that contain no module import or export declarations are classified as scripts. Scripts form the single global namespace and entities declared in scripts are in scope everywhere in a program.

  ImplementationScript:
   ImplementationScriptElementsopt

  ImplementationScriptElements:
   ImplementationScriptElement
   ImplementationScriptElementsImplementationScriptElement

  ImplementationScriptElement:
   ImplementationElement
   AmbientModuleDeclaration

  ImplementationElement:
   Statement
   LexicalDeclaration
   FunctionDeclaration
   GeneratorDeclaration
   ClassDeclaration
   InterfaceDeclaration
   TypeAliasDeclaration
   EnumDeclaration
   NamespaceDeclaration
   AmbientDeclaration
   ImportAliasDeclaration

  DeclarationScript:
   DeclarationScriptElementsopt

  DeclarationScriptElements:
   DeclarationScriptElement
   DeclarationScriptElementsDeclarationScriptElement

  DeclarationScriptElement:
   DeclarationElement
   AmbientModuleDeclaration

  DeclarationElement:
   InterfaceDeclaration
   TypeAliasDeclaration
   NamespaceDeclaration
   AmbientDeclaration
   ImportAliasDeclaration

The initialization order of the scripts that make up the global namespace ultimately depends on the order in which the generated JavaScript files are loaded at run-time (which, for example, may be controlled by <script/> tags that reference the generated JavaScript files).

11.3 Modules

Source files that contain at least one module import or export declaration are considered separate modules. Non-exported entities declared in a module are in scope only in that module, but exported entities can be imported into other modules using import declarations.

  ImplementationModule:
   ImplementationModuleElementsopt

  ImplementationModuleElements:
   ImplementationModuleElement
   ImplementationModuleElementsImplementationModuleElement

  ImplementationModuleElement:
   ImplementationElement
   ImportDeclaration
   ImportAliasDeclaration
   ImportRequireDeclaration
   ExportImplementationElement
   ExportDefaultImplementationElement
   ExportListDeclaration
   ExportAssignment

  DeclarationModule:
   DeclarationModuleElementsopt

  DeclarationModuleElements:
   DeclarationModuleElement
   DeclarationModuleElementsDeclarationModuleElement

  DeclarationModuleElement:
   DeclarationElement
   ImportDeclaration
   ImportAliasDeclaration
   ExportDeclarationElement
   ExportDefaultDeclarationElement
   ExportListDeclaration
   ExportAssignment

Initialization order of modules is determined by the module loader being used and is not specified by the TypeScript language. However, it is generally the case that non-circularly dependent modules are automatically loaded and initialized in the correct order.

Modules can additionally be declared using AmbientModuleDeclarations in declaration scripts that directly specify the module names as string literals. This is described further in section 12.2.

下面是用单独的源文件编写的两个模块的示例:

// -------- main.ts --------  
import { message } from "./log";  
message("hello");

// -------- log.ts --------  
export function message(s: string) {  
    console.log(s);  
}

" main"模块中的导入声明引用了" log"模块,编译" main.ts"文件会使" log.ts"文件也作为程序的一部分进行编译.

TypeScript支持模块的多种JavaScript代码生成模式:

  • CommonJS. 服务器框架(例如node.js)使用此格式.
  • AMD(异步模块定义). 异步模块加载程序(例如RequireJS)使用此格式.
  • UMD(通用模块定义). AMD格式的一种变体,它允许CommonJS加载程序也加载模块.
  • 系统. 此格式用于在下层环境中以高保真度表示ECMAScript 2015语义.

所需的模块代码生成模式是通过编译器选项选择的,并且不会影响TypeScript源代码. 确实,可以编写可编译为在服务器端(例如,使用node.js)和客户端(使用AMD兼容加载器)上使用的模块,而无需更改TypeScript源代码.

11.3.1 Module Names

使用模块名称标识和引用模块. 以下定义与 CommonJS Modules 1.0规范中提供的定义一致 .

  • 模块名称是一串用正斜杠分隔的术语.
  • 模块名称可能没有文件扩展名,例如" .js".
  • 模块名称可以是相对的或顶级的. 如果第一个术语是"",则模块名称是相对的. 要么 "..".
  • 顶级名称是从概念模块名称空间根目录解析的.
  • 相对名称是相对于其出现的模块名称来解析的.

为了解决模块引用,TypeScript将文件路径与每个模块关联. 文件路径仅是模块源文件的路径,而没有文件扩展名. 例如,包含在源文件" C:\ src \ lib \ io.ts"中的模块具有文件路径" C:/ src / lib / io",而包含在源文件" C:\ src \ ui \ editor.d.ts"的文件路径为" C:/ src / ui / editor".

导入声明中的模块名称解析如下:

  • 如果导入声明指定了相对模块名称,则相对于引用模块文件路径的目录来解析该名称. 该程序必须包含具有结果文件路径的模块,否则会发生错误. 例如,在文件路径为" C:/ src / ui / main"的模块中,模块名称" ./editor"和" ../lib/io"引用的文件路径为" C:/ src / ui / editor"和" C:/ src / lib / io".
  • 如果导入声明指定了顶级模块名称,并且程序包含AmbientModuleDeclaration (第12.2节),其字符串文字指定了该确切名称,则导入声明将引用该环境模块.
  • 如果导入声明指定顶级模块名称,并且程序不包含带有指定该确切名称的字符串文字的AmbientModuleDeclaration (第12.2节),则以主机相关的方式解析名称(例如,通过考虑相对于名称的名称)模块名称空间根目录). 如果找不到匹配的模块,则会发生错误.

11.3.2 Import Declarations

Import declarations are used to import entities from other modules and provide bindings for them in the current module.

An import declaration of the form

import * as m from "mod";

imports the module with the given name and creates a local binding for the module itself. The local binding is classified as a value (representing the module instance) and a namespace (representing a container of types and namespaces).

An import declaration of the form

import { x, y, z } from "mod";

导入给定的模块,并为模块的导出成员的指定列表创建本地绑定. 指定的名称必须每个都引用给定模块的导出成员集中( 11.3.4.4 )中的一个实体 . 本地绑定与其表示的实体具有相同的名称和分类,除非使用as子句指定不同的本地名称:

import { x as a, y as b } from "mod";

表格的进口声明

import d from "mod";

与进口申报完全相同

import { default as d } from "mod";

表格的进口声明

import "mod";

导入给定的模块而不创建任何本地绑定(仅在导入的模块有副作用的情况下才有用).

11.3.3 Import Require Declarations

Import require declarations exist for backward compatibility with earlier versions of TypeScript.

  ImportRequireDeclaration:
   importBindingIdentifier=require(StringLiteral);

导入require声明引入了引用给定模块的本地标识符. 导入require声明中指定的字符串文字被解释为模块名称(第 11.3.1 ). 声明引入的本地标识符成为从引用模块导出的实体的别名,并按照与之完全相同的方式进行分类. 具体来说,如果引用的模块不包含导出分配,则将标识符分类为值和名称空间,如果引用的模块包含导出分配,则将标识符进行分类,就像在导出分配中命名的实体一样.

导入需要以下形式的声明

import m = require("mod");

等效于ECMAScript 2015导入声明

import * as m from "mod";

provided the referenced module contains no export assignment.

11.3.4 Export Declarations

An export declaration declares one or more exported module members. The exported members of a module can be imported in other modules using import declarations (11.3.2).

11.3.4.1 Export Modifiers

In the body of a module, a declaration can export the declared entity by including an export modifier.

  ExportImplementationElement:
   exportVariableStatement
   exportLexicalDeclaration
   exportFunctionDeclaration
   exportGeneratorDeclaration
   exportClassDeclaration
   exportInterfaceDeclaration
   exportTypeAliasDeclaration
   exportEnumDeclaration
   exportNamespaceDeclaration
   exportAmbientDeclaration
   exportImportAliasDeclaration

  ExportDeclarationElement:
   exportInterfaceDeclaration
   exportTypeAliasDeclaration
   exportAmbientDeclaration
   exportImportAliasDeclaration

In addition to introducing a name in the local declaration space of the module, an exported declaration introduces the same name with the same classification in the module's export declaration space. For example, the declaration

export function point(x: number, y: number) {  
    return { x, y };  
}

introduces a local name point and an exported name point that both reference the function.

11.3.4.2 Export Default Declarations

Export default declarations provide short-hand syntax for exporting an entity named default.

  ExportDefaultImplementationElement:
   exportdefaultFunctionDeclaration
   exportdefaultGeneratorDeclaration
   exportdefaultClassDeclaration
   exportdefaultAssignmentExpression;

  ExportDefaultDeclarationElement:
   exportdefaultAmbientFunctionDeclaration
   exportdefaultAmbientClassDeclaration
   exportdefaultIdentifierReference;

An ExportDefaultImplementationElement or ExportDefaultDeclarationElement for a function, generator, or class introduces a value named default, and in the case of a class, a type named default, in the containing module's export declaration space. The declaration may optionally specify a local name for the exported function, generator, or class. For example, the declaration

export default function point(x: number, y: number) {  
    return { x, y };  
}

introduces a local name point and an exported name default that both reference the function. The declaration is effectively equivalent to

function point(x: number, y: number) {  
    return { x, y };  
}

export default point;

which again is equivalent to

function point(x: number, y: number) {  
    return { x, y };  
}

export { point as default };

An ExportDefaultImplementationElement or ExportDefaultDeclarationElement for an expression consisting of a single identifier must name an entity declared in the current module or the global namespace. The declaration introduces an entity named default, with the same classification as the referenced entity, in the containing module's export declaration space. For example, the declarations

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

function Point(x: number, y: number): Point {  
    return { x, y };  
}

export default Point;

introduce a local name Point and an exported name default, both with a value and a type meaning.

An ExportDefaultImplementationElement for any expression but a single identifier introduces a value named default in the containing module's export declaration space. For example, the declaration

export default "hello";

introduces an exported value named default of type string.

11.3.4.3 Export List Declarations

An export list declaration exports one or more entities from the current module or a specified module.

  ExportListDeclaration:
   export*FromClause;
   exportExportClauseFromClause;
   exportExportClause;

An ExportListDeclaration without a FromClause exports entities from the current module. In a declaration of the form

export { x };

the name x must reference an entity declared in the current module or the global namespace, and the declaration introduces an entity with the same name and meaning in the containing module's export declaration space.

An ExportListDeclaration with a FromClause re-exports entities from a specified module. In a declaration of the form

export { x } from "mod";

the name x must reference an entity in the export member set of the specified module, and the declaration introduces an entity with the same name and meaning in the containing module's export declaration space. No local bindings are created for x.

The ExportClause of an ExportListDeclaration can specify multiple entities and may optionally specify different names to be used for the exported entities. For example, the declaration

export { x, y as b, z as c };

introduces entities named x, b, and c in the containing module's export declaration space with the same meaning as the local entities named x, y, and z respectively.

An ExportListDeclaration that specifies * instead of an ExportClause is called an export star declaration. An export star declaration re-exports all members of a specified module.

export * from "mod";

Explicitly exported members take precedence over members re-exported using export star declarations, as described in the following section.

11.3.4.4 Export Member Set

The export member set of a particular module is determined by starting with an empty set of members E and an empty set of processed modules P, and then processing the module as described below to form the full set of exported members in E. Processing a module M consists of these steps:

  • Add M to P.
  • Add to E each member in the export declaration space of M with a name that isn't already in E.
  • For each export star declaration in M, in order of declaration, process the referenced module if it is not already in P.

A module's instance type is an object type with a property for each member in the module's export member set that denotes a value.

If a module contains an export assignment it is an error for the module to also contain export declarations. The two types of exports are mutually exclusive.

11.3.5 Export Assignments

Export assignments exist for backward compatibility with earlier versions of TypeScript. An export assignment designates a module member as the entity to be exported in place of the module itself.

  ExportAssignment:
   export=IdentifierReference;

可以使用导入需求声明( 11.3.3导入包含导出分配的模块 ,然后导入需求声明引入的本地别名将具有导出分配中命名的标识符的所有含义.

包含导出分配的模块也可以使用常规导入声明( 11.3.2 )导入,前提是导出分配中引用的实体声明为名称空间或带有类型注释的变量.

假设以下示例位于文件" point.ts"中:

export = Point;

class Point {  
    constructor(public x: number, public y: number) { }  
    static origin = new Point(0, 0);  
}

当在另一个模块中导入" point.ts"时,导入别名引用导出的类,并且可以用作类型和构造函数:

import Pt = require("./point");

var p1 = new Pt(10, 20);  
var p2 = Pt.origin;

注意,不要求导入别名使用与导出实体相同的名称.

11.3.6 CommonJS Modules

CommonJS的模块定义指定用于隐含隐私,导入其他模块的能力,并且能够明确地输出部件编写JavaScript组件的方法. 符合CommonJS的系统提供了一个'require'函数,该函数可用于同步加载其他模块以获取其单例模块实例,以及一个'exports'变量,模块可以向其添加属性以定义其外部API.

上面的11.3节中的" main"和" log"示例在为CommonJS Modules模式编译时生成以下JavaScript代码:

文件main.js:

var log_1 = require("./log");  
log_1.message("hello");

文件log.js:

function message(s) {  
    console.log(s);  
}  
exports.message = message;

模块导入声明在生成的JavaScript中表示为变量,该变量通过调用模块系统主机提供的" require"函数进行初始化. 仅当导入模块或引用导入模块的本地别名(第10.3节)在导入模块主体中的某个地方称为PrimaryExpression时 ,才会为特定的导入模块发出变量声明和'require'调用. 如果仅将导入的模块引用为NamespaceNameTypeQueryExpression ,则不会发出任何内容.

一个例子:

文件geometry.ts:

export interface Point { x: number; y: number };

export function point(x: number, y: number): Point {  
    return { x, y };  
}

档案game.ts:

import * as g from "./geometry";  
let p = g.point(10, 20);

"游戏"模块在表达式中(通过其别名" g")引用导入的"几何"模块,因此在发出的JavaScript中包含了"要求"调用:

var g = require("./geometry");  
var p = g.point(10, 20);

取而代之的是将"游戏"模块写为仅在类型位置引用"几何"

import * as g from "./geometry";  
let p: g.Point = { x: 10, y: 20 };

发出的JavaScript将不依赖于'geometry'模块,而仅仅是

var p = { x: 10, y: 20 };

11.3.7 AMD Modules

The Asynchronous Module Definition (AMD) specification extends the CommonJS Modules specification with a pattern for authoring asynchronously loadable modules with associated dependencies. Using the AMD pattern, modules are emitted as calls to a global 'define' function taking an array of dependencies, specified as module names, and a callback function containing the module body. The global 'define' function is provided by including an AMD compliant loader in the application. The loader arranges to asynchronously load the module's dependencies and, upon completion, calls the callback function passing resolved module instances as arguments in the order they were listed in the dependency array.

当为AMD模式编译时,上面的" main"和" log"示例生成以下JavaScript代码.

文件main.js:

define(["require", "exports", "./log"], function(require, exports, log_1) {  
    log_1.message("hello");  
}

文件log.js:

define(["require", "exports"], function(require, exports) {  
    function message(s) {  
        console.log(s);  
    }  
    exports.message = message;  
}

始终存在特殊的"需要"和"导出"依赖项. 根据需要,其他条目会添加到依赖项数组和参数列表中,以表示导入的模块. 与CommonJS Modules的代码生成类似,只有在导入模块主体中某处将导入模块引用为PrimaryExpression时,才会为特定的导入模块生成依赖项. 如果仅将导入的模块引用为NamespaceName ,则不会为该模块生成依赖关系.


12 Ambients

Ambient declarations are used to provide static typing over existing JavaScript code. Ambient declarations differ from regular declarations in that no JavaScript code is emitted for them. Instead of introducing new variables, functions, classes, enums, or namespaces, ambient declarations provide type information for entities that exist "ambiently" and are included in a program by external means, for example by referencing a JavaScript library in a <script/> tag.

12.1 Ambient Declarations

Ambient declarations are written using the declare keyword and can declare variables, functions, classes, enums, namespaces, or modules.

  AmbientDeclaration:
   declareAmbientVariableDeclaration
   declareAmbientFunctionDeclaration
   declareAmbientClassDeclaration
   declareAmbientEnumDeclaration
   declareAmbientNamespaceDeclaration

12.1.1 Ambient Variable Declarations

An ambient variable declaration introduces a variable in the containing declaration space.

  AmbientVariableDeclaration:
   varAmbientBindingList;
   letAmbientBindingList;
   constAmbientBindingList;

  AmbientBindingList:
   AmbientBinding
   AmbientBindingList,AmbientBinding

  AmbientBinding:
   BindingIdentifierTypeAnnotationopt

An ambient variable declaration may optionally include a type annotation. If no type annotation is present, the variable is assumed to have type Any.

An ambient variable declaration does not permit an initializer expression to be present.

12.1.2 Ambient Function Declarations

An ambient function declaration introduces a function in the containing declaration space.

  AmbientFunctionDeclaration:
   functionBindingIdentifierCallSignature;

通过指定多个具有相同名称的环境函数声明可以重载环境函数,但是声明多个被视为相同(第 3.11.2节 )或仅在返回类型上有所不同的重载是错误的 .

环境函数声明不能​​指定函数体,也不允许默认参数值.

12.1.3 Ambient Class Declarations

An ambient class declaration declares a class type and a constructor function in the containing declaration space.

  AmbientClassDeclaration:
   classBindingIdentifierTypeParametersoptClassHeritage{AmbientClassBody}

  AmbientClassBody:
   AmbientClassBodyElementsopt

  AmbientClassBodyElements:
   AmbientClassBodyElement
   AmbientClassBodyElementsAmbientClassBodyElement

  AmbientClassBodyElement:
   AmbientConstructorDeclaration
   AmbientPropertyMemberDeclaration
   IndexSignature

  AmbientConstructorDeclaration:
   constructor(ParameterListopt);

  AmbientPropertyMemberDeclaration:
   AccessibilityModifieroptstaticoptPropertyNameTypeAnnotationopt;
   AccessibilityModifieroptstaticoptPropertyNameCallSignature;

12.1.4 Ambient Enum Declarations

An ambient enum is grammatically equivalent to a non-ambient enum declaration.

  AmbientEnumDeclaration:
   EnumDeclaration

Ambient enum declarations differ from non-ambient enum declarations in two ways:

  • In ambient enum declarations, all values specified in enum member declarations must be classified as constant enum expressions.
  • In ambient enum declarations that specify no const modifier, enum member declarations that omit a value are considered computed members (as opposed to having auto-incremented values assigned).

Ambient enum declarations are otherwise processed in the same manner as non-ambient enum declarations.

12.1.5 Ambient Namespace Declarations

An ambient namespace declaration declares a namespace.

  AmbientNamespaceDeclaration:
   namespaceIdentifierPath{AmbientNamespaceBody}

  AmbientNamespaceBody:
   AmbientNamespaceElementsopt

  AmbientNamespaceElements:
   AmbientNamespaceElement
   AmbientNamespaceElementsAmbientNamespaceElement

  AmbientNamespaceElement:
   exportoptAmbientVariableDeclaration
   exportoptAmbientLexicalDeclaration
   exportoptAmbientFunctionDeclaration
   exportoptAmbientClassDeclaration
   exportoptInterfaceDeclaration
   exportoptAmbientEnumDeclaration
   exportoptAmbientNamespaceDeclaration
   exportoptImportAliasDeclaration

Except for ImportAliasDeclarations, AmbientNamespaceElements always declare exported entities regardless of whether they include the optional export modifier.

12.2 Ambient Module Declarations

AmbientModuleDeclaration声明一个模块. 仅在有助于全局命名空间的源文件的顶级允许这种类型的声明(第 11.1 ). StringLiteral必须指定顶级模块名称. 不允许使用相对模块名称.

  AmbientModuleDeclaration:
   declaremoduleStringLiteral{DeclarationModule}

AmbientModuleDeclaration中ImportRequireDeclaration只能通过顶级模块名称引用其他模块. 不允许使用相对模块名称.

如果环境模块声明包含导出分配,则模块内的任何声明指定export修饰符都是错误的. 如果环境模块声明不包含导出分配,则将导出模块中声明的实体,无论其声明是否包括可选的export修饰符.

环境模块是"开放式"的,具有相同字符串文字名称的环境模块声明构成单个模块. 例如,模块" io"的以下两个声明可能位于单独的源文件中.

declare module "io" {  
    export function readFile(filename: string): string;  
}

declare module "io" {  
    export function writeFile(filename: string, data: string): void;  
}

这与单个组合声明具有相同的效果:

declare module "io" {  
    export function readFile(filename: string): string;  
    export function writeFile(filename: string, data: string): void;  
}

A Grammar

本附录包含在主文档中找到的语法摘要. 如第 2.1 节所述 ,TypeScript语法是ECMAScript 2015语言规范 (特别是ECMA-262标准,第6版)中定义的语法的超集,并且本附录仅列出从ECMAScript语法中新增或修改的产品.

A.1 Types

  TypeParameters:
   <TypeParameterList>

  TypeParameterList:
   TypeParameter
   TypeParameterList,TypeParameter

  TypeParameter:
   BindingIdentifierConstraintopt

  Constraint:
   extendsType

  TypeArguments:
   <TypeArgumentList>

  TypeArgumentList:
   TypeArgument
   TypeArgumentList,TypeArgument

  TypeArgument:
   Type

  Type:
   UnionOrIntersectionOrPrimaryType
   FunctionType
   ConstructorType

  UnionOrIntersectionOrPrimaryType:
   UnionType
   IntersectionOrPrimaryType

  IntersectionOrPrimaryType:
   IntersectionType
   PrimaryType

  PrimaryType:
   ParenthesizedType
   PredefinedType
   TypeReference
   ObjectType
   ArrayType
   TupleType
   TypeQuery
   ThisType

  ParenthesizedType:
   (Type)

  PredefinedType:
   any
   number
   boolean
   string
   symbol
   void

  TypeReference:
   TypeName[no LineTerminator here]TypeArgumentsopt

  TypeName:
   IdentifierReference
   NamespaceName.IdentifierReference

  NamespaceName:
   IdentifierReference
   NamespaceName.IdentifierReference

  ObjectType:
   {TypeBodyopt}

  TypeBody:
   TypeMemberList;opt
   TypeMemberList,opt

  TypeMemberList:
   TypeMember
   TypeMemberList;TypeMember
   TypeMemberList,TypeMember

  TypeMember:
   PropertySignature
   CallSignature
   ConstructSignature
   IndexSignature
   MethodSignature

  ArrayType:
   PrimaryType[no LineTerminator here][]

  TupleType:
   [TupleElementTypes]

  TupleElementTypes:
   TupleElementType
   TupleElementTypes,TupleElementType

  TupleElementType:
   Type

  UnionType:
   UnionOrIntersectionOrPrimaryType|IntersectionOrPrimaryType

  IntersectionType:
   IntersectionOrPrimaryType&PrimaryType

  FunctionType:
   TypeParametersopt(ParameterListopt)=>Type

  ConstructorType:
   newTypeParametersopt(ParameterListopt)=>Type

  TypeQuery:
   typeofTypeQueryExpression

  TypeQueryExpression:
   IdentifierReference
   TypeQueryExpression.IdentifierName

  ThisType:
   this

  PropertySignature:
   PropertyName?optTypeAnnotationopt

  PropertyName:
   IdentifierName
   StringLiteral
   NumericLiteral

  TypeAnnotation:
   :Type

  CallSignature:
   TypeParametersopt(ParameterListopt)TypeAnnotationopt

  ParameterList:
   RequiredParameterList
   OptionalParameterList
   RestParameter
   RequiredParameterList,OptionalParameterList
   RequiredParameterList,RestParameter
   OptionalParameterList,RestParameter
   RequiredParameterList,OptionalParameterList,RestParameter

  RequiredParameterList:
   RequiredParameter
   RequiredParameterList,RequiredParameter

  RequiredParameter:
   AccessibilityModifieroptBindingIdentifierOrPatternTypeAnnotationopt
   BindingIdentifier:StringLiteral

  AccessibilityModifier:
   public
   private
   protected

  BindingIdentifierOrPattern:
   BindingIdentifier
   BindingPattern

  OptionalParameterList:
   OptionalParameter
   OptionalParameterList,OptionalParameter

  OptionalParameter:
   AccessibilityModifieroptBindingIdentifierOrPattern?TypeAnnotationopt
   AccessibilityModifieroptBindingIdentifierOrPatternTypeAnnotationoptInitializer
   BindingIdentifier?:StringLiteral

  RestParameter:
   ...BindingIdentifierTypeAnnotationopt

  ConstructSignature:
   newTypeParametersopt(ParameterListopt)TypeAnnotationopt

  IndexSignature:
   [BindingIdentifier:string]TypeAnnotation
   [BindingIdentifier:number]TypeAnnotation

  MethodSignature:
   PropertyName?optCallSignature

  TypeAliasDeclaration:
   typeBindingIdentifierTypeParametersopt=Type;

A.2 Expressions

  PropertyDefinition: ( Modified )
   IdentifierReference
   CoverInitializedName
   PropertyName:AssignmentExpression
   PropertyNameCallSignature{FunctionBody}
   GetAccessor
   SetAccessor

  GetAccessor:
   getPropertyName()TypeAnnotationopt{FunctionBody}

  SetAccessor:
   setPropertyName(BindingIdentifierOrPatternTypeAnnotationopt){FunctionBody}

  FunctionExpression: ( Modified )
   functionBindingIdentifieroptCallSignature{FunctionBody}

  ArrowFormalParameters: ( Modified )
   CallSignature

  Arguments: ( Modified )
   TypeArgumentsopt(ArgumentListopt)

  UnaryExpression: ( Modified )
   …
   <Type>UnaryExpression

A.3 Statements

  Declaration: ( Modified )
   …
   InterfaceDeclaration
   TypeAliasDeclaration
   EnumDeclaration

  VariableDeclaration: ( Modified )
   SimpleVariableDeclaration
   DestructuringVariableDeclaration

  SimpleVariableDeclaration:
   BindingIdentifierTypeAnnotationoptInitializeropt

  DestructuringVariableDeclaration:
   BindingPatternTypeAnnotationoptInitializer

  LexicalBinding: ( Modified )
   SimpleLexicalBinding
   DestructuringLexicalBinding

  SimpleLexicalBinding:
   BindingIdentifierTypeAnnotationoptInitializeropt

  DestructuringLexicalBinding:
   BindingPatternTypeAnnotationoptInitializeropt

A.4 Functions

  FunctionDeclaration: ( Modified )
   functionBindingIdentifieroptCallSignature{FunctionBody}
   functionBindingIdentifieroptCallSignature;

A.5 Interfaces

  InterfaceDeclaration:
   interfaceBindingIdentifierTypeParametersoptInterfaceExtendsClauseoptObjectType

  InterfaceExtendsClause:
   extendsClassOrInterfaceTypeList

  ClassOrInterfaceTypeList:
   ClassOrInterfaceType
   ClassOrInterfaceTypeList,ClassOrInterfaceType

  ClassOrInterfaceType:
   TypeReference

A.6 Classes

  ClassDeclaration: ( Modified )
   classBindingIdentifieroptTypeParametersoptClassHeritage{ClassBody}

  ClassHeritage: ( Modified )
   ClassExtendsClauseoptImplementsClauseopt

  ClassExtendsClause:
   extendsClassType

  ClassType:
   TypeReference

  ImplementsClause:
   implementsClassOrInterfaceTypeList

  ClassElement: ( Modified )
   ConstructorDeclaration
   PropertyMemberDeclaration
   IndexMemberDeclaration

  ConstructorDeclaration:
   AccessibilityModifieroptconstructor(ParameterListopt){FunctionBody}
   AccessibilityModifieroptconstructor(ParameterListopt);

  PropertyMemberDeclaration:
   MemberVariableDeclaration
   MemberFunctionDeclaration
   MemberAccessorDeclaration

  MemberVariableDeclaration:
   AccessibilityModifieroptstaticoptPropertyNameTypeAnnotationoptInitializeropt;

  MemberFunctionDeclaration:
   AccessibilityModifieroptstaticoptPropertyNameCallSignature{FunctionBody}
   AccessibilityModifieroptstaticoptPropertyNameCallSignature;

  MemberAccessorDeclaration:
   AccessibilityModifieroptstaticoptGetAccessor
   AccessibilityModifieroptstaticoptSetAccessor

  IndexMemberDeclaration:
   IndexSignature;

A.7 Enums

  EnumDeclaration:
   constoptenumBindingIdentifier{EnumBodyopt}

  EnumBody:
   EnumMemberList,opt

  EnumMemberList:
   EnumMember
   EnumMemberList,EnumMember

  EnumMember:
   PropertyName
   PropertyName = EnumValue

  EnumValue:
   AssignmentExpression

A.8 Namespaces

  NamespaceDeclaration:
   namespaceIdentifierPath{NamespaceBody}

  IdentifierPath:
   BindingIdentifier
   IdentifierPath.BindingIdentifier

  NamespaceBody:
   NamespaceElementsopt

  NamespaceElements:
   NamespaceElement
   NamespaceElementsNamespaceElement

  NamespaceElement:
   Statement
   LexicalDeclaration
   FunctionDeclaration
   GeneratorDeclaration
   ClassDeclaration
   InterfaceDeclaration
   TypeAliasDeclaration
   EnumDeclaration
   NamespaceDeclaration
   AmbientDeclaration
   ImportAliasDeclaration
   ExportNamespaceElement

  ExportNamespaceElement:
   exportVariableStatement
   exportLexicalDeclaration
   exportFunctionDeclaration
   exportGeneratorDeclaration
   exportClassDeclaration
   exportInterfaceDeclaration
   exportTypeAliasDeclaration
   exportEnumDeclaration
   exportNamespaceDeclaration
   exportAmbientDeclaration
   exportImportAliasDeclaration

  ImportAliasDeclaration:
   importBindingIdentifier=EntityName;

  EntityName:
   NamespaceName
   NamespaceName.IdentifierReference

A.9 Scripts and Modules

  SourceFile:
   ImplementationSourceFile
   DeclarationSourceFile

  ImplementationSourceFile:
   ImplementationScript
   ImplementationModule

  DeclarationSourceFile:
   DeclarationScript
   DeclarationModule

  ImplementationScript:
   ImplementationScriptElementsopt

  ImplementationScriptElements:
   ImplementationScriptElement
   ImplementationScriptElementsImplementationScriptElement

  ImplementationScriptElement:
   ImplementationElement
   AmbientModuleDeclaration

  ImplementationElement:
   Statement
   LexicalDeclaration
   FunctionDeclaration
   GeneratorDeclaration
   ClassDeclaration
   InterfaceDeclaration
   TypeAliasDeclaration
   EnumDeclaration
   NamespaceDeclaration
   AmbientDeclaration
   ImportAliasDeclaration

  DeclarationScript:
   DeclarationScriptElementsopt

  DeclarationScriptElements:
   DeclarationScriptElement
   DeclarationScriptElementsDeclarationScriptElement

  DeclarationScriptElement:
   DeclarationElement
   AmbientModuleDeclaration

  DeclarationElement:
   InterfaceDeclaration
   TypeAliasDeclaration
   NamespaceDeclaration
   AmbientDeclaration
   ImportAliasDeclaration

  ImplementationModule:
   ImplementationModuleElementsopt

  ImplementationModuleElements:
   ImplementationModuleElement
   ImplementationModuleElementsImplementationModuleElement

  ImplementationModuleElement:
   ImplementationElement
   ImportDeclaration
   ImportAliasDeclaration
   ImportRequireDeclaration
   ExportImplementationElement
   ExportDefaultImplementationElement
   ExportListDeclaration
   ExportAssignment

  DeclarationModule:
   DeclarationModuleElementsopt

  DeclarationModuleElements:
   DeclarationModuleElement
   DeclarationModuleElementsDeclarationModuleElement

  DeclarationModuleElement:
   DeclarationElement
   ImportDeclaration
   ImportAliasDeclaration
   ExportDeclarationElement
   ExportDefaultDeclarationElement
   ExportListDeclaration
   ExportAssignment

  ImportRequireDeclaration:
   importBindingIdentifier=require(StringLiteral);

  ExportImplementationElement:
   exportVariableStatement
   exportLexicalDeclaration
   exportFunctionDeclaration
   exportGeneratorDeclaration
   exportClassDeclaration
   exportInterfaceDeclaration
   exportTypeAliasDeclaration
   exportEnumDeclaration
   exportNamespaceDeclaration
   exportAmbientDeclaration
   exportImportAliasDeclaration

  ExportDeclarationElement:
   exportInterfaceDeclaration
   exportTypeAliasDeclaration
   exportAmbientDeclaration
   exportImportAliasDeclaration

  ExportDefaultImplementationElement:
   exportdefaultFunctionDeclaration
   exportdefaultGeneratorDeclaration
   exportdefaultClassDeclaration
   exportdefaultAssignmentExpression;

  ExportDefaultDeclarationElement:
   exportdefaultAmbientFunctionDeclaration
   exportdefaultAmbientClassDeclaration
   exportdefaultIdentifierReference;

  ExportListDeclaration:
   export*FromClause;
   exportExportClauseFromClause;
   exportExportClause;

  ExportAssignment:
   export=IdentifierReference;

A.10 Ambients

  AmbientDeclaration:
   declareAmbientVariableDeclaration
   declareAmbientFunctionDeclaration
   declareAmbientClassDeclaration
   declareAmbientEnumDeclaration
   declareAmbientNamespaceDeclaration

  AmbientVariableDeclaration:
   varAmbientBindingList;
   letAmbientBindingList;
   constAmbientBindingList;

  AmbientBindingList:
   AmbientBinding
   AmbientBindingList,AmbientBinding

  AmbientBinding:
   BindingIdentifierTypeAnnotationopt

  AmbientFunctionDeclaration:
   functionBindingIdentifierCallSignature;

  AmbientClassDeclaration:
   classBindingIdentifierTypeParametersoptClassHeritage{AmbientClassBody}

  AmbientClassBody:
   AmbientClassBodyElementsopt

  AmbientClassBodyElements:
   AmbientClassBodyElement
   AmbientClassBodyElementsAmbientClassBodyElement

  AmbientClassBodyElement:
   AmbientConstructorDeclaration
   AmbientPropertyMemberDeclaration
   IndexSignature

  AmbientConstructorDeclaration:
   constructor(ParameterListopt);

  AmbientPropertyMemberDeclaration:
   AccessibilityModifieroptstaticoptPropertyNameTypeAnnotationopt;
   AccessibilityModifieroptstaticoptPropertyNameCallSignature;

  AmbientEnumDeclaration:
   EnumDeclaration

  AmbientNamespaceDeclaration:
   namespaceIdentifierPath{AmbientNamespaceBody}

  AmbientNamespaceBody:
   AmbientNamespaceElementsopt

  AmbientNamespaceElements:
   AmbientNamespaceElement
   AmbientNamespaceElementsAmbientNamespaceElement

  AmbientNamespaceElement:
   exportoptAmbientVariableDeclaration
   exportoptAmbientLexicalDeclaration
   exportoptAmbientFunctionDeclaration
   exportoptAmbientClassDeclaration
   exportoptInterfaceDeclaration
   exportoptAmbientEnumDeclaration
   exportoptAmbientNamespaceDeclaration
   exportoptImportAliasDeclaration

  AmbientModuleDeclaration:
   declaremoduleStringLiteral{DeclarationModule}

您目前无法执行该操作.

by  ICOPY.SITE