TypeScript 1.6

JSX 支持

¥JSX support

JSX 是一种可嵌入的类 XML 语法。它旨在转换为有效的 JavaScript,但该转换的语义是特定于实现的。JSX 因 React 库而流行起来,但后来也出现在了其他应用中。TypeScript 1.6 支持嵌入、类型检查以及可选地将 JSX 直接编译到 JavaScript 中。

¥JSX is an embeddable XML-like syntax. It is meant to be transformed into valid JavaScript, but the semantics of that transformation are implementation-specific. JSX came to popularity with the React library but has since seen other applications. TypeScript 1.6 supports embedding, type checking, and optionally compiling JSX directly into JavaScript.

新的 .tsx 文件扩展名和 as 运算符

¥New .tsx file extension and as operator

TypeScript 1.6 引入了新的 .tsx 文件扩展名。此扩展有两个作用:它在 TypeScript 文件中启用 JSX,并且使新的 as 运算符成为默认的类型转换方式(消除了 JSX 表达式和 TypeScript 前缀类型转换运算符之间的任何歧义)。例如:

¥TypeScript 1.6 introduces a new .tsx file extension. This extension does two things: it enables JSX inside of TypeScript files, and it makes the new as operator the default way to cast (removing any ambiguity between JSX expressions and the TypeScript prefix cast operator). For example:

ts
var x = <any>foo;
// is equivalent to:
var x = foo as any;

使用 React

¥Using React

要在 React 中使用 JSX 支持,你应该使用 React 类型。这些类型定义了 JSX 命名空间,以便 TypeScript 能够正确检查 React 的 JSX 表达式。例如:

¥To use JSX-support with React you should use the React typings. These typings define the JSX namespace so that TypeScript can correctly check JSX expressions for React. For example:

ts
/// <reference path="react.d.ts" />
interface Props {
name: string;
}
class MyComponent extends React.Component<Props, {}> {
render() {
return <span>{this.props.name}</span>;
}
}
<MyComponent name="bar" />; // OK
<MyComponent name={0} />; // error, `name` is not a number

使用其他 JSX 框架

¥Using other JSX frameworks

JSX 元素名称和属性会根据 JSX 命名空间进行验证。请参阅 [[JSX]] wiki 页面,了解如何为你的框架定义 JSX 命名空间。

¥JSX element names and properties are validated against the JSX namespace. Please see the [[JSX]] wiki page for defining the JSX namespace for your framework.

输出生成

¥Output generation

TypeScript 附带两种 JSX 模式:preservereact

¥TypeScript ships with two JSX modes: preserve and react.

  • preserve 模式会将 JSX 表达式保留为输出的一部分,以供其他转换步骤使用。此外,输出将具有 .jsx 文件扩展名。

    ¥The preserve mode will keep JSX expressions as part of the output to be further consumed by another transform step. Additionally the output will have a .jsx file extension.

  • react 模式会触发 React.createElement,使用前不需要经过 JSX 转换,输出会有 .js 文件扩展名。

    ¥The react mode will emit React.createElement, does not need to go through a JSX transformation before use, and the output will have a .js file extension.

有关在 TypeScript 中使用 JSX 的更多信息,请参阅 [[JSX]] 维基页面。

¥See the [[JSX]] wiki page for more information on using JSX in TypeScript.

交叉类型

¥Intersection types

TypeScript 1.6 引入了交叉类型,即联合类型的逻辑补充。联合类型 A | B 表示一个实体,该实体的类型可以是 AB,而交叉类型 A & B 表示一个实体,该实体的类型可以是 AB

¥TypeScript 1.6 introduces intersection types, the logical complement of union types. A union type A | B represents an entity that is either of type A or type B, whereas an intersection type A & B represents an entity that is both of type A and type B.

示例

¥Example

ts
function extend<T, U>(first: T, second: U): T & U {
let result = <T & U>{};
for (let id in first) {
result[id] = first[id];
}
for (let id in second) {
if (!result.hasOwnProperty(id)) {
result[id] = second[id];
}
}
return result;
}
var x = extend({ a: "hello" }, { b: 42 });
var s = x.a;
var n = x.b;
ts
type LinkedList<T> = T & { next: LinkedList<T> };
interface Person {
name: string;
}
var people: LinkedList<Person>;
var s = people.name;
var s = people.next.name;
var s = people.next.next.name;
var s = people.next.next.next.name;
ts
interface A {
a: string;
}
interface B {
b: string;
}
interface C {
c: string;
}
var abc: A & B & C;
abc.a = "hello";
abc.b = "hello";
abc.c = "hello";

有关详细信息,请参阅 问题 #1256

¥See issue #1256 for more information.

本地类型声明

¥Local type declarations

局部类、接口、枚举和类型别名声明现在可以出现在函数声明中。局部类型具有块作用域,类似于使用 letconst 声明的变量。例如:

¥Local class, interface, enum, and type alias declarations can now appear inside function declarations. Local types are block scoped, similar to variables declared with let and const. For example:

ts
function f() {
if (true) {
interface T {
x: number;
}
let v: T;
v.x = 5;
} else {
interface T {
x: string;
}
let v: T;
v.x = "hello";
}
}

推断出的函数返回类型可能是函数内部声明的类型。函数调用者无法引用这样的本地类型,但当然可以通过结构匹配。例如:

¥The inferred return type of a function may be a type declared locally within the function. It is not possible for callers of the function to reference such a local type, but it can of course be matched structurally. For example:

ts
interface Point {
x: number;
y: number;
}
function getPointFactory(x: number, y: number) {
class P {
x = x;
y = y;
}
return P;
}
var PointZero = getPointFactory(0, 0);
var PointOne = getPointFactory(1, 1);
var p1 = new PointZero();
var p2 = new PointZero();
var p3 = new PointOne();

局部类型可以引用封闭的类型参数,并且局部类和接口本身可以是泛型的。例如:

¥Local types may reference enclosing type parameters and local class and interfaces may themselves be generic. For example:

ts
function f3() {
function f<X, Y>(x: X, y: Y) {
class C {
public x = x;
public y = y;
}
return C;
}
let C = f(10, "hello");
let v = new C();
let x = v.x; // number
let y = v.y; // string
}

类表达式

¥Class expressions

TypeScript 1.6 增加了对 ES6 类表达式的支持。在类表达式中,类名是可选的,如果指定,则仅在类表达式本身的范围内有效。这类似于函数表达式的可选名称。无法在类表达式之外引用类表达式的类实例类型,但该类型当然可以通过结构匹配。例如:

¥TypeScript 1.6 adds support for ES6 class expressions. In a class expression, the class name is optional and, if specified, is only in scope in the class expression itself. This is similar to the optional name of a function expression. It is not possible to refer to the class instance type of a class expression outside the class expression, but the type can of course be matched structurally. For example:

ts
let Point = class {
constructor(public x: number, public y: number) {}
public length() {
return Math.sqrt(this.x * this.x + this.y * this.y);
}
};
var p = new Point(3, 4); // p has anonymous class type
console.log(p.length());

扩展表达式

¥Extending expressions

TypeScript 1.6 增加了对扩展任意表达式的类的支持,该表达式计算构造函数。这意味着现在可以在类声明中扩展内置类型。

¥TypeScript 1.6 adds support for classes extending arbitrary expression that computes a constructor function. This means that built-in types can now be extended in class declarations.

类的 extends 子句以前需要指定类型引用。现在它接受一个表达式,后面可选地跟着一个类型参数列表。表达式的类型必须是构造函数类型,且至少有一个构造函数签名的类型参数数量与 extends 子句中指定的类型参数数量相同。匹配构造签名的返回类型是类实例类型继承的基类型。实际上,这允许在 extends 子句中指定实数类和 “class-like” 表达式。

¥The extends clause of a class previously required a type reference to be specified. It now accepts an expression optionally followed by a type argument list. The type of the expression must be a constructor function type with at least one construct signature that has the same number of type parameters as the number of type arguments specified in the extends clause. The return type of the matching construct signature(s) is the base type from which the class instance type inherits. Effectively, this allows both real classes and “class-like” expressions to be specified in the extends clause.

一些例子:

¥Some examples:

ts
// Extend built-in types
class MyArray extends Array<number> {}
class MyError extends Error {}
// Extend computed base class
class ThingA {
getGreeting() {
return "Hello from A";
}
}
class ThingB {
getGreeting() {
return "Hello from B";
}
}
interface Greeter {
getGreeting(): string;
}
interface GreeterConstructor {
new (): Greeter;
}
function getGreeterBase(): GreeterConstructor {
return Math.random() >= 0.5 ? ThingA : ThingB;
}
class Test extends getGreeterBase() {
sayHello() {
console.log(this.getGreeting());
}
}

abstract 类和方法

¥abstract classes and methods

TypeScript 1.6 增加了对类及其方法的 abstract 关键字的支持。抽象类允许包含没有实现的方法,并且不能被构造。

¥TypeScript 1.6 adds support for abstract keyword for classes and their methods. An abstract class is allowed to have methods with no implementation, and cannot be constructed.

示例

¥Examples

ts
abstract class Base {
abstract getThing(): string;
getOtherThing() {
return "hello";
}
}
let x = new Base(); // Error, 'Base' is abstract
// Error, must either be 'abstract' or implement concrete 'getThing'
class Derived1 extends Base {}
class Derived2 extends Base {
getThing() {
return "hello";
}
foo() {
super.getThing(); // Error: cannot invoke abstract members through 'super'
}
}
var x = new Derived2(); // OK
var y: Base = new Derived2(); // Also OK
y.getThing(); // OK
y.getOtherThing(); // OK

泛型类型别名

¥Generic type aliases

使用 TypeScript 1.6,类型别名可以是泛型的。例如:

¥With TypeScript 1.6, type aliases can be generic. For example:

ts
type Lazy<T> = T | (() => T);
var s: Lazy<string>;
s = "eager";
s = () => "lazy";
interface Tuple<A, B> {
a: A;
b: B;
}
type Pair<T> = Tuple<T, T>;

更严格的对象字面量赋值检查

¥Stricter object literal assignment checks

TypeScript 1.6 强制执行更严格的对象字面量赋值检查,以捕获多余或拼写错误的属性。具体来说,当将新的对象字面量赋值给变量或作为非空目标类型的参数传递时,如果对象字面量指定了目标类型中不存在的属性,则会出错。

¥TypeScript 1.6 enforces stricter object literal assignment checks for the purpose of catching excess or misspelled properties. Specifically, when a fresh object literal is assigned to a variable or passed as an argument for a non-empty target type, it is an error for the object literal to specify properties that don’t exist in the target type.

示例

¥Examples

ts
var x: { foo: number };
x = { foo: 1, baz: 2 }; // Error, excess property `baz`
var y: { foo: number; bar?: number };
y = { foo: 1, baz: 2 }; // Error, excess or misspelled property `baz`

类型可以包含索引签名,以明确指示允许使用多余的属性:

¥A type can include an index signature to explicitly indicate that excess properties are permitted:

ts
var x: { foo: number; [x: string]: any };
x = { foo: 1, baz: 2 }; // Ok, `baz` matched by index signature

ES6 生成器

¥ES6 generators

TypeScript 1.6 在面向 ES6 时增加了对生成器的支持。

¥TypeScript 1.6 adds support for generators when targeting ES6.

生成器函数可以像函数一样拥有返回类型注解。注解表示函数返回的生成器的类型。这是一个例子:

¥A generator function can have a return type annotation, just like a function. The annotation represents the type of the generator returned by the function. Here is an example:

ts
function* g(): Iterable<string> {
for (var i = 0; i < 100; i++) {
yield ""; // string is assignable to string
}
yield* otherStringGenerator(); // otherStringGenerator must be iterable and element type assignable to string
}

没有类型注解的生成器函数可以推断出其类型注解。因此在以下情况下,类型将从 yield 语句推断出来:

¥A generator function with no type annotation can have the type annotation inferred. So in the following case, the type will be inferred from the yield statements:

ts
function* g() {
for (var i = 0; i < 100; i++) {
yield ""; // infer string
}
yield* otherStringGenerator(); // infer element type of otherStringGenerator
}

实验性支持 async 函数

¥Experimental support for async functions

TypeScript 1.6 在面向 ES6 时引入了对 async 函数的实验性支持。异步函数预期会调用异步操作并等待其结果,而不会阻塞程序的正常执行。这是通过使用与 ES6 兼容的 Promise 实现,并将函数体转置为兼容形式,以便在等待的异步操作完成后恢复执行来实现的。

¥TypeScript 1.6 introduces experimental support of async functions when targeting ES6. Async functions are expected to invoke an asynchronous operation and await its result without blocking normal execution of the program. This accomplished through the use of an ES6-compatible Promise implementation, and transposition of the function body into a compatible form to resume execution when the awaited asynchronous operation completes.

异步函数是带有 async 修饰符前缀的函数或方法。此修饰符告知编译器需要进行函数体转置,并且关键字 await 应被视为一元表达式,而不是标识符。异步函数必须提供指向兼容 Promise 类型的返回类型注解。只有存在全局定义的、兼容的 Promise 类型时,才能使用返回类型推断。

¥An async function is a function or method that has been prefixed with the async modifier. This modifier informs the compiler that function body transposition is required, and that the keyword await should be treated as a unary expression instead of an identifier. An Async Function must provide a return type annotation that points to a compatible Promise type. Return type inference can only be used if there is a globally defined, compatible Promise type.

示例

¥Example

ts
var p: Promise<number> = /* ... */;
async function fn(): Promise<number> {
var i = await p; // suspend execution until 'p' is settled. 'i' has type "number"
return 1 + i;
}
var a = async (): Promise<number> => 1 + await p; // suspends execution.
var a = async () => 1 + await p; // suspends execution. return type is inferred as "Promise<number>" when compiling with --target ES6
var fe = async function(): Promise<number> {
var i = await p; // suspend execution until 'p' is settled. 'i' has type "number"
return 1 + i;
}
class C {
async m(): Promise<number> {
var i = await p; // suspend execution until 'p' is settled. 'i' has type "number"
return 1 + i;
}
async get p(): Promise<number> {
var i = await p; // suspend execution until 'p' is settled. 'i' has type "number"
return 1 + i;
}
}

夜间构建

¥Nightly builds

虽然严格来说这并非语言变更,但现在可以通过以下命令安装夜间构建版本:

¥While not strictly a language change, nightly builds are now available by installing with the following command:

npm install -g typescript@next

模块解析逻辑调整

¥Adjustments in module resolution logic

从 1.6 版本开始,TypeScript 编译器在针对 ‘commonjs’ 运行时将使用不同的规则来解析模块名称。这些 rules 试图模拟 Node 使用的模块查找过程。这实际上意味着 Node 模块可以包含有关其类型的信息,并且 TypeScript 编译器将能够找到它。但是,用户可以使用 moduleResolution 命令行选项覆盖编译器选择的模块解析规则。可能的值包括:

¥Starting from release 1.6 TypeScript compiler will use different set of rules to resolve module names when targeting ‘commonjs’. These rules attempted to model module lookup procedure used by Node. This effectively mean that node modules can include information about its typings and TypeScript compiler will be able to find it. User however can override module resolution rules picked by the compiler by using moduleResolution command line option. Possible values are:

  • ‘classic’ - 1.6 之前的 TypeScript 编译器使用的模块解析规则

    ¥‘classic’ - module resolution rules used by pre 1.6 TypeScript compiler

  • ‘node’ - 类似 Node 的模块解析

    ¥‘node’ - node-like module resolution

合并环境类和接口声明

¥Merging ambient class and interface declaration

环境类声明的实例端可以使用接口声明进行扩展,类构造函数对象未经修改。例如:

¥The instance side of an ambient class declaration can be extended using an interface declaration The class constructor object is unmodified. For example:

ts
declare class Foo {
public x: number;
}
interface Foo {
y: string;
}
function bar(foo: Foo) {
foo.x = 1; // OK, declared in the class Foo
foo.y = "1"; // OK, declared in the interface Foo
}

用户定义的类型保护函数

¥User-defined type guard functions

除了 typeofinstanceof 之外,TypeScript 1.6 还添加了一种在 if 块内缩小变量类型的新方法。用户定义的类型保护函数的返回类型注释形式为 x is T,其中 x 是签名中声明的参数,T 可以是任意类型。当在 if 块中的变量上调用用户定义的类型保护函数时,该变量的类型将被缩减为 T

¥TypeScript 1.6 adds a new way to narrow a variable type inside an if block, in addition to typeof and instanceof. A user-defined type guard functions is one with a return type annotation of the form x is T, where x is a declared parameter in the signature, and T is any type. When a user-defined type guard function is invoked on a variable in an if block, the type of the variable will be narrowed to T.

示例

¥Examples

ts
function isCat(a: any): a is Cat {
return a.name === "kitty";
}
var x: Cat | Dog;
if (isCat(x)) {
x.meow(); // OK, x is Cat in this block
}

tsconfig.json 中支持 exclude 属性

¥exclude property support in tsconfig.json

未指定 files 属性(因此隐式引用了所有子目录中的所有 *.ts 文件)的 tsconfig.json 文件现在可以包含一个 exclude 属性,该属性指定要从编译中排除的文件和/或目录列表。exclude 属性必须是一个字符串数组,每个字符串指定一个相对于 tsconfig.json 文件位置的文件或文件夹名称。例如:

¥A tsconfig.json file that doesn’t specify a files property (and therefore implicitly references all *.ts files in all subdirectories) can now contain an exclude property that specifies a list of files and/or directories to exclude from the compilation. The exclude property must be an array of strings that each specify a file or folder name relative to the location of the tsconfig.json file. For example:

{
"": "test.js"
},
"": ["node_modules", "test.ts", "utils/t2.ts"]
}

exclude 列表不支持通配符。它必须只是一个文件和/或目录的列表。

¥The exclude list does not support wildcards. It must simply be a list of files and/or directories.

--init 命令行选项

¥--init command line option

在目录中运行 tsc --init 以使用预设的默认值在该目录中创建初始 tsconfig.json。可选地,在创建时将命令行参数与 --init 一起传递,以便存储在初始 tsconfig.json 中。

¥Run tsc --init in a directory to create an initial tsconfig.json in this directory with preset defaults. Optionally pass command line arguments along with --init to be stored in your initial tsconfig.json on creation.