TypeScript 1.8

TypeScript 1.8

Type 参数作为约束

使用 TypeScript 1.8,可以使用类型参数约束从相同的类型参数列表中引用类型参数。以前这是一个错误。这种能力通常被称为 F-Bounded Polymorphism

示例

function assign<T extends U, U>(target: T, source: U): T { for (let id in source) { target[id] = source[id]; } return target; } let x = { a: 1, b: 2, c: 3, d: 4 }; assign(x, { b: 10, d: 20 } assign(x, { e: 0 } // Error

控制流量分析错误

TypeScript 1.8 引入了控制流分析来帮助捕捉用户倾向于遇到的常见错误。请阅读以获取更多详细信息,并查看这些错误的实际操作:

无法访问的代码

保证不会在运行时执行的语句现在可以正确标记为不可达代码错误。例如,下面的语句无条件的returnthrowbreakcontinue语句被认为是不可到达的。使用--allowUnreachableCode禁用可达代码检测和报告。

示例

以下是一个无法访问的代码错误的简单示例:

function f(x) { if (x) { return true; } else { return false; } x = 0; // Error: Unreachable code detected. }

此功能捕获的更常见的错误是在return语句后添加换行符:

function f() { return // Automatic Semicolon Insertion triggered at newline { x: "string" // Error: Unreachable code detected. } }

由于 JavaScript 在行尾自动终止return语句,因此对象字面量变为块。

未使用的标签

未使用的标签也被标记。就像无法访问的代码检查一样,这些默认情况下都会打开; 用于--allowUnusedLabels停止报告这些错误。

示例

loop: while (x > 0) { // Error: Unused label. x++; }

隐式返回

具有不返回 JS 值的代码路径的函数隐式返回undefined。这些现在可以被编译器标记为隐式返回。该检查默认关闭 ; 使用--noImplicitReturns打开它。

示例

function f(x) { // Error: Not all code paths return a value. if (x) { return false; } // implicitly returns `undefined` }

案例条款落后

在 case 子句非空的 switch 语句中,TypeScript 可以报告错误情况。该检查默认关闭,可以使用启用--noFallthroughCasesInSwitch

示例

有了--noFallthroughCasesInSwitch这个例子会触发一个错误:

switch (x % 2) { case 0: // Error: Fallthrough case in switch. console.log("even" case 1: console.log("odd" break; }

但是,在下面的示例中,由于落空情况为空,因此不会报告错误:

switch (x % 3) { case 0: case 1: console.log("Acceptable" break; case 2: console.log("This is *two much*!" break; }

React 中的无状态函数组件

TypeScript 现在支持无状态函数组件。这些是轻松构成其他组件的轻量级组件:

// Use parameter destructuring and defaults for easy definition of 'props' type const Greeter = {name = 'world'}) => <div>Hello, {name}!</div>; // Properties get validated let example = <Greeter name='TypeScript 1.8' />;

对于这个功能和简化的道具,一定要使用 react.d.ts 的最新版本

React中简化的props类型管理

在带有最新版本 react.d.ts 的 TypeScript 1.8 中(见上),我们也大大简化了props类型的声明。

特别:

  • 您不再需要显式声明refkeyextend React.Props

  • refkey性能会出现正确的类型上的所有组件

  • ref属性在无状态函数组件的实例中被正确禁止

从模块中增加全局/模块范围

用户现在可以声明他们想要创建的任何扩展,或者任何其他使用者已经创建的扩展到现有模块。模块增强看起来像普通的旧环境模块声明(即declare module "foo" { }语法),并且直接嵌套在您自己的模块中,或者直接嵌套在另一个顶级环境外部模块中。

此外,TypeScript 还具有表单全局增强的概念declare global { }。这允许模块增加全局类型(Array如有必要)。

模块扩充的名称使用与模块说明符相同的一组规则importexport声明来解决。模块扩充中的声明以与在同一文件中声明的方式相同的方式与任何现有声明合并。

模块增强和全局增强都不能将新项添加到顶层作用域 - 它们只能“修补”现有的声明。

示例

这里map.ts可以声明它将在内部修补Observable类型observable.ts并将map方法添加到它。

// observable.ts export class Observable<T> { // ... }

// map.ts import { Observable } from "./observable"; // Create an augmentation for "./observable" declare module "./observable" { // Augment the 'Observable' class definition with interface merging interface Observable<T> { map<U>(proj: (el: T) => U): Observable<U>; } } Observable.prototype.map = /*...*/;

// consumer.ts import { Observable } from "./observable"; import "./map"; let o: Observable<number>; o.map(x => x.toFixed()

同样,全局范围可以通过使用declare global声明的模块进行扩充:

示例

// Ensure this is treated as a module. export {}; declare global { interface Array<T> { mapToNumbers(): number[]; } } Array.prototype.mapToNumbers = function () { /* ... */ }

字符串文字类型

API 对于某些值期望一组特定的字符串并不罕见。例如,考虑一个 UI 库,它可以在控制动画的“缓动”的同时在屏幕上移动元素。

declare class UIElement { animate(options: AnimationOptions): void; } interface AnimationOptions { deltaX: number; deltaY: number; easing: string; // Can be "ease-in", "ease-out", "ease-in-out" }

但是,这很容易出错 - 没有任何东西阻止用户意外地拼错其中一个有效缓动值:

// No errors new UIElement().animate{ deltaX: 100, deltaY: 100, easing: "ease-inout" }

使用 TypeScript 1.8,我们引入了字符串文字类型。这些类型的书写方式与字符串文字相同,但是在类型位置。

用户现在可以确保类型系统会捕获这样的错误。这里是我们新AnimationOptions使用的字符串文字类型:

interface AnimationOptions { deltaX: number; deltaY: number; easing: "ease-in" | "ease-out" | "ease-in-out"; } // Error: Type '"ease-inout"' is not assignable to type '"ease-in" | "ease-out" | "ease-in-out"' new UIElement().animate{ deltaX: 100, deltaY: 100, easing: "ease-inout" }

改进的联合/交叉类型推断

TypeScript 1.8改进了涉及源和目标边的类型推断,它们都是联合或交集类型。例如,从当推断string | string[]string | T,我们减少类型string[]T,从而推断string[]T

示例

type Maybe<T> = T | void; function isDefined<T>(x: Maybe<T>): x is T { return x !== undefined && x !== null; } function isUndefined<T>(x: Maybe<T>): x is void { return x === undefined || x === null; } function getOrElse<T>(x: Maybe<T>, defaultValue: T): T { return isDefined(x) ? x : defaultValue; } function test1(x: Maybe<string>) { let x1 = getOrElse(x, "Undefined" // string let x2 = isDefined(x) ? x : "Undefined"; // string let x3 = isUndefined(x) ? "Undefined" : x; // string } function test2(x: Maybe<number>) { let x1 = getOrElse(x, -1 // number let x2 = isDefined(x) ? x : -1; // number let x3 = isUndefined(x) ? -1 : x; // number }

--outFil连接AMD和System模块

指定--outFile连接--module amd--module system将连接编译中的所有模块到包含多个模块闭包的单个输出文件中。

将根据每个模块的相对位置计算模块名称rootDir

示例

// file src/a.ts import * as B from "./lib/b"; export function createA() { return B.createB( }

// file src/lib/b.ts export function createB() { return { }; }

结果是:

define("lib/b", ["require", "exports"], function (require, exports) { "use strict"; function createB() { return {}; } exports.createB = createB; } define("a", ["require", "exports", "lib/b"], function (require, exports, B) { "use strict"; function createA() { return B.createB( } exports.createA = createA; }

支持default与 SystemJS 进行互操作

像 SystemJS 这样的模块加载程序将 CommonJS 模块封装起来,然后作为defaultES6 导入进行公开。这使得不可能在模块的 SystemJS 和 CommonJS 实现之间共享定义文件,因为根据加载器,模块形状看起来不同。

设置新的编译器标志--allowSyntheticDefaultImports表明模块加载器执行某种在导入的 .ts 或 .d.ts 中未指示的合成默认导入成员创建。编译器会推断出default具有整个模块本身形状的导出。

系统模块默认打开此标志。

允许捕获let/ const循环

以前是 TypeScript 1.8 现在支持的错误。let/ const循环内的声明和函数捕获现在发射到正确匹配let/ const新鲜语义。

示例

let list = []; for (let i = 0; i < 5; i++) { list.push(() => i } list.forEach(f => console.log(f())

被编译为:

var list = []; var _loop_1 = function(i) { list.push(function () { return i; } }; for (var i = 0; i < 5; i++) { _loop_1(i } list.forEach(function (f) { return console.log(f() }

并在结果中

0 1 2 3 4

改进了对for..in语句的检查

以前,for..in变量的类型被推断为any; 这允许编译器忽略for..in正文中的无效用途。

从 TypeScript 1.8 开始:

  • for..in语句中声明的变量的类型是隐含的string

  • 当具有数字索引签名类型T(例如数组)的对象通过包含具有数字索引签名并且没有字符串索引签名(又如数组)的对象for..in的包含for..in语句的变量进行索引时,生成的值是类型的T

示例

var a: MyObject[]; for (var x in a) { // Type of x is implicitly string var obj = a[x]; // Type of obj is MyObject }

模块现在发布了"use strict";序言

根据 ES6,模块始终在严格模式下进行解析,但对于非ES6目标,这在生成的代码中不受重视。从 TypeScript 1.8 开始,发射模块始终处于严格模式。在大多数代码中,这不应该有任何明显的变化,因为 TS 在编译时将最严格的模式错误视为错误,但这意味着一些过去在 TS 代码中运行时以静默方式失败的东西,比如赋值NaN,现在将大声地失败。您可以参考严格模式下的 MDN 文章,了解严格模式和非严格模式之间差异的详细清单。

包含.js文件--allowJs

通常在您的项目中有外部源文件,可能不会在 TypeScript 中创作。或者,您可能正在将 JS 代码库转换为 TS,但仍希望将所有 JS 代码与新 TS 代码的输出捆绑到一个文件中。

.js现在允许文件作为输入tsc。TypeScript 编译器检查输入.js文件的语法错误,并根据--target--module标志发出有效输出。输出也可以与其他.ts文件结合使用。源.js文件仍然像.ts文件一样为文件生成。

自定义 JSX 工厂使用 --reactNamespace

--reactNamespace <JSX factory Name>一起传递--jsx react允许使用默认的React不同 JSX 工厂。

新的工厂名称将用于调用createElement__spread功能。

示例

import {jsxFactory} from "jsxFactory"; var div = <div>Hello JSX!</div>

编译:

tsc --jsx react --reactNamespace jsxFactory --m commonJS

结果是:

"use strict"; var jsxFactory_1 = require("jsxFactory" var div = jsxFactory_1.jsxFactory.createElement("div", null, "Hello JSX!"

this型卫士

TypeScript 1.8将用户定义的类型保护函数扩展到类和接口方法。

this is T现在是类和接口中方法的有效返回类型注释。当用于类型缩减位置(例如if语句)时,调用表达式目标对象的类型将缩小到T

示例

class FileSystemObject { isFile(): this is File { return this instanceof File; } isDirectory(): this is Directory { return this instanceof Directory;} isNetworked(): this is (Networked & this) { return this.networked; } constructor(public path: string, private networked: boolean) {} } class File extends FileSystemObject { constructor(path: string, public content: string) { super(path, false } } class Directory extends FileSystemObject { children: FileSystemObject[]; } interface Networked { host: string; } let fso: FileSystemObject = new File("foo/bar.txt", "foo" if (fso.isFile()) { fso.content; // fso is File } else if (fso.isDirectory()) { fso.children; // fso is Directory } else if (fso.isNetworked()) { fso.host; // fso is networked }

官方 TypeScript NuGet 包

从 TypeScript 1.8 开始,官方 NuGet 包可用于 Typescript Compiler(tsc.exe)以及 MSBuild 集成(Microsoft.TypeScript.targetsMicrosoft.TypeScript.Tasks.dll)。

稳定的软件包可在这里找到:

此外,myget上还提供了一个夜间NuGet包,以匹配夜间npm包

  • TypeScript-Preview来自tsc我们的漂亮的错误信息我们明白,大量的单色输出在眼睛上可能有点困难。颜色可以帮助辨别哪里的消息开始和结束,而这些视觉线索是重要的,当错误输出得到overwhelming.By刚好路过的--pretty命令行选项,打字稿给人以情境更加丰富多彩输出何处事情会出错。

  • 如果添加tsconfig.json文件,则不会编译不被视为该上下文一部分的 TypeScript 文件。

  • Apache Cordova Apps 仍然具有单个tsconfig.json文件的现有限制,该文件必须位于根目录或scripts文件夹中。

  • 大多数项目类型没有tsconfig.json模板。