TypeScript 1.6

TypeScript 1.6

JSX支持

JSX是一种可嵌入XML的语法。它意味着被转换成有效的JavaScript,但该转换的语义是特定于实现的。JSX开始受到React库的欢迎,但后来又看到了其他应用程序。TypeScript 1.6支持嵌入,类型检查以及可选地将JSX直接编译为JavaScript。

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

TypeScript 1.6引入了新的.tsx文件扩展名。这个扩展做了两件事:它使JSX在TypeScript文件内部起作用,并使新as操作符成为默认的强制转换方式(消除了JSX表达式和TypeScript前缀转换操作符之间的任何歧义)。例如:

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

使用React

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

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

使用其他JSX framworks

JSX元素名称和属性根据JSX名称空间进行验证。请参阅[JSX] wiki页面来JSX为您的框架定义命名空间。

输出产生

TypeScript附带两种JSX模式:preservereact

  • preserve模式将使JSX表达式作为输出的一部分被另一个转换步骤进一步消耗。此外,输出将具有 文件扩展名。.jsx

  • react模式将发出React.createElement,在使用之前不需要经过JSX转换,并且输出将具有.js文件扩展名。

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

相交类型

TypeScript 1.6引入了交集类型,这是联合类型的逻辑补充。甲联合类型A | B表示是任一类型的实体A或类型B,而交叉路口类型A & B表示既是类型的实体A 类型B

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;

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;

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

本地类型声明

局部类,接口,枚举和类型别名声明现在可以出现在函数声明中。局部类型是块范围的,类似于用letand 声明的变量const。例如:

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

函数的推断返回类型可以是在函数内本地声明的类型。函数的调用者不可能引用这样的局部类型,但它当然可以在结构上匹配。例如:

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(

本地类型可能引用封闭类型参数,本地类和接口本身可能是通用的。例如:

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 }

类表达式

TypeScript 1.6增加了对ES6类表达式的支持。在类表达式中,类名是可选的,如果指定的话,它只在类表达式本身的范围内。这与函数表达式的可选名称类似。不能在类表达式之外引用类表达式的类实例类型,但类型当然可以在结构上匹配。例如:

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

扩展表达式

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

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

一些例子:

// 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 类和方法

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

例子

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

泛型类型别名

使用TypeScript 1.6时,输入别名可以是通用的。例如:

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

更严格的对象文字分配检查

TypeScript 1.6强制执行更严格的对象文字分配检查,以捕获过量或拼写错误的属性。特别是,当新的对象字面量被分配给变量或作为非空目标类型的参数传递时,对象字面值会指定目标类型中不存在的属性。

例子

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`

一个类型可以包含索引签名以明确指示允许超出的属性:

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

ES6产生器

定位ES6时,TypeScript 1.6增加了对生成器的支持。

生成器函数可以具有返回类型注释,就像函数一样。该注释表示该函数返回的生成器的类型。这里是一个例子:

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语句中推断出该类型:

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

async功能的实验支持

在针对ES6时,TypeScript 1.6引入了异步功能的实验支持。 预计异步函数将调用异步操作并等待其结果,而不会阻止程序的正常执行。 这通过使用兼容ES6的Promise实现完成,并将函数体转换为兼容的形式,以便在等待的异步操作完成时恢复执行。

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

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

每晚式建立

虽然不是严格意义上的语言变更,但通过使用以下命令进行安装,现在可以使用夜间版本:

npm install -g typescript@next

模块分辨率逻辑中的调整

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

  • 'classic' - 由1.6版前的TypeScript编译器使用的模块解析规则

  • '节点' - 类似节点的模块分辨率

合并环境类和接口声明

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

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 }

用户定义的类型保护功能

除了typeof和instanceof之外,TypeScript 1.6还增加了一种新的方法来缩小if块内的变量类型。 用户定义的类型保护函数是一个具有返回类型注释的形式,其中x是T,其中x是签名中声明的参数,T是任何类型。 当一个用户定义的类型保护函数被调用时,变量的类型将被缩小到T.

例子

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 }

exclude 在tsconfig.json中支持属性

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

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

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

--init 命令行选项

tsc --init在目录中运行,tsconfig.json以预设的默认值在该目录中创建一个初始值。可以选择传递命令行参数,并将--init其存储在创建时的初始tsconfig.json中。