TypeScript 3.0! 是的,他出来了,它确实有很多创新。 在页面的下方,您将找到所有最新创新的详细描述,包括构建模式,未知的新类型,对API的重大更改,性能改进等等。 立即加入!

TypeScript 3.0发布! 开发TypeScript(所有JavaScript用户的助手)的道路上已经有了一个新的里程碑。
如果您不熟悉TypeScript,现在开始学习它还为时不晚! TypeScript是一个JavaScript扩展,旨在在此静态类型语言的现代版本中使用。 TypeScript编译器读取TypeScript代码,其中特别包含类型声明和类型注释,并生成干净,易于阅读的JavaScript代码,在其中转换和删除了这些结构。 生成的代码可以在符合ECMAScript标准的任何运行时环境中运行,例如,在您喜欢的浏览器或Node.js服务器平台上。
使用这样的环境意味着在用户启动代码之前,将对代码进行分析以检查错误或错别字,但其优势不限于此。 借助所有这些信息和分析结果,TimeScript通过在您喜欢的编辑器中提供自动代码完成和导航工具(例如“查找所有引用”,“转到定义”和“重命名”)来增强可用性。 。
要开始使用该语言并获取更多信息,请单击
链接 。 如果您想立即尝试TypeScript 3.0,则可以通过键入以下内容从
NuGet或npm下载它
npm install -g typescript
此外,以下编辑器中提供了支持:
其他编辑器会根据自己的时间表进行更新,但是很快他们将都拥有出色的TypeScript支持。
3.0版概述
在TypeScript 2.0发布之后,我们简要概述了先前版本对其当前状态的贡献。 在TypeScript 1.0和2.0的发行版之间,该语言包括联合类型,类型防护,对现代ECMAScript标准的支持,类型别名,JSX支持,文字和多态
this
类型。 如果您包括未启用null的TypeScript 2.0类型,控制流分析,对标记联合的支持,这种类型以及用于接收
.d.ts
文件的简化模型,那么我们可以说这段时间完全确定了基础知识。 TypeScript的工作。
那么自那以来做了什么? 除了ECMAScript标准的新功能,例如
async
/
await
异步函数,生成器和rest / spread运算符之外,是什么促使我们进入TypeScript 3.0?
TypeScript 2.1成为基本版本,它在JavaScript中引入了静态元编程模型。 密钥请求(
keyof
),索引访问(
T[K]
)和映射对象的类型(
{ [K in keyof T]: } T[K]}
)-这是一系列工具,用于更有效地对React,Ember库进行建模, Lodash和其他人。
TypeScript 2.2和2.3版本引入了对混合类模板,
object
类型(表示非原始对象的对象)以及泛型类型的默认值的支持。 这些功能已在许多项目中使用,例如Angular Material和Polymer。 另外,TypeScript 2.3引入了微调
this
类型的功能,使该语言可以与Vue之类的库一起很好地工作,并
checkJs
了
checkJs
标志以允许在JavaScript文件中检查类型。
TypeScript 2.4和2.6延续了增加函数类型检查的严重性的故事,该类型与我们类型系统的某些最古老的评论相关联。 引入了
--strictFunctionTypes
标志,以强制参数相互矛盾。 在2.7版中,严谨的趋势一直存在,并且已在使用
--strictPropertyInitialization
标志的类中进行了验证。
TypeScript 2.8引入了条件类型,这是用于静态表达基于类型的决策的强大工具,而2.9版则推广了keyof运算符并简化了类型的导入。
这使我们进入TypeScript 3.0! 尽管数字中增加了新的整数,但3.0版中的更改很少(这意味着更新非常容易)。 它引入了一种新的灵活和可扩展的方法来构造项目,对参数列表进行工作的强大新支持,用于提供显式检查的新类型,改进的JSX支持,显着更加用户友好的错误诊断等等。
最新消息
- 项目链接
- 使用元组检索和分配参数列表
- 新的元组类型功能
- 类型
unknown
- 改进的错误诊断和用户环境
- 支持JSX中的
defaultProps
属性 - 指令
/// <reference lib="..." />
- 提高编辑速度
- 重构命名的导入语句
- 结束标签末端和轮廓框
- 快速修复无法访问的代码和未使用的标签
- 重大变化
项目链接
通常,要构建库或应用程序,您需要执行几个步骤。 假设您的代码库包含
src
和
test
目录。 假设您有一个存储应用程序客户端代码的客户
client
文件夹,以及一个包含Node.js平台上服务器代码的服务器文件夹,每个文件夹都从
shared
文件夹中获取了一部分代码。 也许您正在使用所谓的“单个存储库”,并且有许多项目相互复杂地相互依赖。
我们在发布TypeScript 3.0时所使用的最重要的功能之一被称为“项目链接”,旨在简化使用此类脚本的工作。
由于项目链接,某些TypeScript项目可能依赖于其他项目。 特别是,
tsconfig.json
文件
tsconfig.json
允许引用其他
tsconfig.json
文件。 定义这些依赖项使将代码拆分为较小的项目变得更加容易,因为TypeScript编译器(及其工具)有机会了解组装顺序和输出结构。 这意味着组装更快,并且增量执行(分阶段),并且支持透明导航,编辑和重构各种项目。 由于TypeScript 3.0为该项目奠定了基础并提供了API,因此任何构建工具都应能够提供此功能。
看起来像什么?
这是一个
tsconfig.json
文件,其中包含一个到项目的链接作为一个简单示例。
// ./src/bar/tsconfig.json { "compilerOptions": { // Needed for project references. "composite": true, "declaration": true, // Other options... "outDir": "../../lib/bar", "strict": true, "module": "esnext", "moduleResolution": "node", }, "references": [ { "path": "../foo" } ] }
它具有两个新字段:
composite
和
references
。
references
字段仅指向其他
tsconfig.json
文件(或包含它们的文件夹)。 这里的每个链接只是一个带有
path
字段(“ path”)的对象,并告诉TypeScript编译器要构建此项目,您必须首先构建它引用的另一个项目。
显然,
composite
领域具有相同的重要性。
composite
字段可确保启用某些参数,以允许依赖于此的任何项目引用它并将其包含在增量构建中。 智能和增量构建的能力很重要,因为可以放弃项目的主要原因之一就是构建速度。
例如,如果
front-end
项目依赖于
shared
项目并在核心上
shared
,那么我们与项目链接相关的API将有助于识别核心中的更改,但是只有在
core
项目产生的类型已更改时(即
.d.ts
文件)。 这意味着核心更改不会导致所有项目的全局重组。 因此,设置
composite
标志也会导致
declaration
标志的设置。
-构建模式
TypeScript 3.0将引入一组用于项目引用的API,以便其他工具可以提供这种快速的增量构建方法。 特别是,gulp-typescript插件已经使用了这些API! 因此,以后到项目的链接将与您选择的装配协调器集成在一起。
但是,对于许多简单的应用程序和库,建议不要使用外部工具。 这就是为什么tsc命令现在设置一个新标志
--build
。
tsc --build
(或其别名
tsc -b
)采用一组项目并进行构建,以及构建相关项目。 使用新的构建模式时,首先,必须设置
--build
标志,并且可以将其与其他标志组合:
--verbose
:显示构建过程所需的每个步骤。--dry
:生成时不生成输出文件(与--verbose
选项结合使用)。–clean
: –clean
删除与指定输入匹配的输出文件。--force
: --force
完整的,非增量的项目构建。
输出结构管理
项目引用的一个微妙但极其有用的优势是将输入文件映射到相应输出文件的逻辑能力。
如果曾经尝试分离应用程序的客户端和服务器部分,则可能会在管理输出结构时遇到问题。
例如,如果对于以下项目,client / index.ts和server / index.ts都引用了shared / index.ts:

...然后当我们尝试构建客户端和服务器项目时,我们得到...

...不...

请注意,在构建之后,我们在客户端和服务器中都收到了共享文件夹的副本。 我们花了额外的时间两次构建共享程序集,并在lib / client / client和lib / server / server中增加了令人讨厌的嵌套级别。
问题在于TypeScript急切地搜索.ts文件,并尝试将其包含在此编译中。 理想情况下,TypeScript应该理解这些文件不应参与同一编译中的程序集,而应转至.d.ts文件以获取类型信息。
为共享创建tsconfig.json文件将完全产生此结果。 它向TypeScript编译器发出信号:
- 共享项目必须独立构建
- 从../shared导入时,我们应该在其输出目录中查找.d.ts文件。
这样可以避免运行双重程序集,也可以避免意外地包含所有共享内容。
未来计划
要更深入地了解设计链接及其使用的可能性,请在
此发行版的
跟踪器中详细了解它们。 在不久的将来,我们将准备有关项目链接和构建模式的文档。
我们努力使其他编程工具的作者可以维护对项目的引用,并就此功能继续改善编辑环境。 我们打算确保使用项目链接的运行与使用一个tsconfig.json文件开发代码一样流畅。 如果您最终开始使用项目链接,我们将不胜感激。
使用元组检索和分配参数列表
我们通常认为这是理所当然的,但是JavaScript允许我们将参数列表视为一流的值-使用参数或类型为rest(例如... rest)的参数。
function call(fn, ...args) { return fn(...args); }
请注意,调用适用于具有任意数量参数的函数。 与其他语言不同,JavaScript不会强制我们如下定义call0,call1,call2等:
function call0(fn) { return fn(); } function call1(fn, param1) { return fn(param1); } function call2(fn, param1, param2) { return fn(param1, param2); } function call3(fn, param1, param2, param3) { return fn(param1, param2, param3); }
不幸的是,有一段时间没有在不声明一定数量的重载的情况下在TypeScript中表达这种方法的好方法:
// TODO (billg): 5 overloads should *probably* be enough for anybody? function call<T1, T2, T3, T4, R>(fn: (param1: T1, param2: T2, param3: T3, param4: T4) => R, param1: T1, param2: T2, param3: T3, param4: T4): R function call<T1, T2, T3, R>(fn: (param1: T1, param2: T2, param3: T3) => R, param1: T1, param2: T2, param3: T3): R function call<T1, T2, R>(fn: (param1: T1, param2: T2) => R, param1: T1, param2: T2): R function call<T1, R>(fn: (param1: T1) => R, param1: T1): R; function call<R>(fn: () => R, param1: T1): R; function call(fn: (...args: any[]) => any, ...args: any[]) { return fn(...args); }
! 一千个超载又导致死亡! 或至少根据用户需要进行许多重载。
TypeScript 3.0允许您更好地模拟这种情况,因为现在其余类型的参数可以是通用的,并且它们的类型定义为元组。 我们不是声明每个重载,而是说fn函数的rest参数... args应该是扩展数组的类型参数,然后将其重用为调用函数传递的... args参数:
function call<TS extends any[], R>(fn: (...args: TS) => R, ...args: TS): R { return fn(...args); }
当我们调用call函数时,TypeScript尝试从传递给fn的内容中提取参数列表,并将其转换为元组:
function foo(x: number, y: string): string { return (x + y).toLowerCase(); } // The `TS` type parameter is inferred as `[number, string]` call(foo, 100, "hello");
当TypeScript将TS定义为[number,string],并且在调用函数的rest参数上完成重用TS时,函数实例如下所示:
function call(fn: (...args: [number, string]) => string, ...args: [number, string]): string
在TypeScript 3.0中,当在其余部分使用元组时,参数将最小化到其余的参数列表! 上面的实例归结为没有元组的简单参数:
function call(fn: (arg1: number, arg2: string) => string, arg1: number, arg2: string): string
因此,除了在传递无效参数时捕获类型转换错误外:
function call<TS extends any[], R>(fn: (...args: TS) => R, ...args: TS): R { return fn(...args); } call((x: number, y: string) => y, "hello", "world"); // ~~~~~~~ // Error! `string` isn't assignable to `number`!
...并从其他参数中输入类型定义:
call((x, y) => { /* .... */ }, "hello", 100); // ^ ^ // `x` and `y` have their types inferred as `string` and `number` respectively.
...我们还可以从外部看到这些函数定义的元组类型:
function tuple<TS extends any[]>(...xs: TS): TS { return xs; } let x = tuple(1, 2, "hello"); // has type `[number, number, string]`
但是要注意一个警告。 为了完成所有这些工作,我们必须扩展元组的功能...
新的元组类型功能
为了将参数列表建模为元组(如我们刚刚讨论的那样),我们不得不重新考虑一下元组类型。 在TypeScript 3.0发行之前,允许使用元组建模的最佳方法是参数集的顺序和长度。
但是,参数列表不仅是有序类型列表。 例如,末尾的参数可以是可选的:
// Both `y` and `z` are optional here. function foo(x: boolean, y = 100, z?: string) { // ... } foo(true); foo(true, undefined, "hello"); foo(true, 200);
最后一个参数可以是rest参数。
// `rest` accepts any number of strings - even none! function foo(...rest: string[]) { // ... } foo(); foo("hello"); foo("hello", "world");
最后,参数列表有一个相当有趣的属性-它们可以为空:
// Accepts no parameters. function foo() { // ... } foo();
因此,为了使元组与参数列表相对应,我们需要模拟每种情况。
首先,现在在元组的末尾可能有可选元素:
/** * 2D, or potentially 3D, coordinate. */ type Coordinate = [number, number, number?];
Coordinate类型会创建一个具有名为2的可选属性的元组-可能未定义索引为2的元素! 有趣的是,由于元组的长度属性使用数字文字类型,因此Coodinate元组的length属性的类型为2 |。 3。
其次,其余元素现在可以出现在元组的末尾。
type OneNumberAndSomeStrings = [number, ...string[]];
多亏了其余元素,元组表现出非常有趣的“从头到尾无限”的行为。 上面的OneNumberAndSomeStrings类型的示例要求其第一个属性的类型为number,并且允许使用string类型的一个或多个属性。 用任意数字索引这种类型的元组将返回字符串类型| 数字,因为索引值未知。 类似地,由于元组的长度是未知的,因此length属性的值就是数字。
应该注意的是,在没有其他元素的情况下,元组中的其余元素与其自身相同:
type Foo = [...number[]]; // Equivalent to `number[]`.
最后,元组现在可以为空! 尽管在参数列表之外使用时这不是很有用,但可以将空元组类型定义为[]:
type EmptyTuple = [];
如您所料,一个空的元组的length属性为0,索引为number的类型从不返回。
改进的错误诊断和用户环境
随着时间的流逝,我们收到越来越多的社区成员关于改进错误消息的请求。 尽管这项工作还远远没有完成,但我们收到了您的来信,并对TypeScript 3.0版本进行了许多改进。
相关误差范围
好的错误消息的部分目的是向用户指示如何纠正它,或者首先是弄清楚为什么出现此消息。 在大多数情况下,它包含许多信息或表明其发生的几种原因。 通过对这些原因的分析,我们可以得出结论,错误是由代码的不同部分导致的。
关联的错误范围是向用户提供此信息的新方法。 在TypeScript 3.0中,错误消息可以在代码中的其他位置生成消息,以便用户可以找出错误的原因和结果。

从某种意义上讲,相关的错误消息不仅可以为用户提供解释,还可以指示出发生一切错误的地方的路径。

在启用--pretty模式的情况下运行tsc命令时,这些间隔也会出现在终端模式下,尽管我们仍在努力改进用户界面并考虑您的反馈!
改进的诊断和错误处理
在准备发布TypeScript 2.9时,我们
开始更加注意错误消息,而在3.0版中,我们确实尝试解决了主要任务,这些任务将使我们能够执行智能,清晰和准确的错误诊断。 这尤其包括在关联类型不一致的情况下选择适当的类型,以及某些类型的消息直接退出错误源。
我们认为我们的努力是有道理的,因此您将收到更短,更清晰的错误消息。


类型未知
类型any是TypeScript中适合任何类型的任何类型。 由于它涵盖了所有可能值的类型,因此不会强迫我们在尝试调用,构造或访问它们的属性之前进行任何检查。 它还允许您将任何类型的值分配给需要其他任何类型的值的变量。
此功能通常很有用,但不能提供足够的严格性。
let foo: any = 10; // All of these will throw errors, but TypeScript // won't complain since `foo` has the type `any`. foo.x.prop; foo.y.prop; foo.z.prop; foo(); new foo(); upperCase(foo); foo `hello world!`; function upperCase(x: string) { return x.toUpperCase(); }
有时在TypeScript中,您想要描述不适合任何类型的类型。 这对于想要发出信号的API很有用:“它可以是任何值,因此您需要在使用它之前进行一些检查。” 并且出于安全原因,用户被迫解析返回值。
TypeScript 3.0引入了一个称为unknown的新类型。 any, unknown , , any, unknown . unknown, .
unknown any, foo :
let foo: unknown = 10; // Since `foo` has type `unknown`, TypeScript // errors on each of these locations. foo.x.prop; foo.y.prop; foo.z.prop; foo(); new foo(); upperCase(foo); foo `hello world!`; function upperCase(x: string) { return x.toUpperCase(); }
, , , .
let foo: unknown = 10; function hasXYZ(obj: any): obj is { x: any, y: any, z: any } { return !!obj && typeof obj === "object" && "x" in obj && "y" in obj && "z" in obj } // Using a user-defined type guard... if (hasXYZ(foo)) { // ...we're allowed to access certain properties again. foo.x.prop; foo.y.prop; foo.z.prop; } // We can also just convince TypeScript we know what we're doing // by using a type assertion. upperCase(foo as string); function upperCase(x: string) { return x.toUpperCase(); }
: , , , {} | null | undefined, unknown , :
type Arrayify<T> = T extends any ? Array<T> : never; type A = Arrayify<{} | null | undefined>; // null[] | undefined[] | {}[] type B = Arrayify<unknown>; // unknown[]
defaultProps JSX
: .d.ts React , , .- TypeScript/JavaScript , , . , . , .
function loudlyGreet(name = "world") { // Thanks to the default initializer, `name` will always have type `string` internally. // We don't have to check for `undefined` here. console.log("HELLO", name.toUpperCase()); } // Externally, `name` is optional, and we can potentially pass `undefined` or omit it entirely. loudlyGreet(); loudlyGreet(undefined);
React (props). React , defaultProps, props.
// Some non-TypeScript JSX file import * as React from "react"; import * as ReactDOM from "react-dom"; export class Greet extends React.Component { render() { const { name } = this.props; return <div>Hello ${name.toUpperCase()}!</div>; } static defaultProps = { name: "world", }; } // Notice no `name` attribute was specified! // vvvvvvvvv const result = ReactDOM.renderToString(<Greet />); console.log(result);
, <Greet /> name. Greet, name «world», : Hello world!.
, TypeScript , defaultProps - JSX. render:
export interface Props { name?: string } export class Greet extends React.Component<Props> { render() { const { name } = this.props;
, .
TypeScript 3.0 JSX, LibraryManagedAttributes. , , TypeScript, JSX. , , React defaultProps , , propTypes.
export interface Props { name: string } export class Greet extends React.Component<Props> { render() { const { name } = this.props; return <div>Hello ${name.toUpperCase()}!</div>; } static defaultProps = { name: "world"} }
, . defaultProps, Partial , - (stateless function components, SFC), defaultProps Partial , . defaultProps (. ) SFC ES2015:
function Greet({ name = "world" }: Props) { return <div>Hello ${name.toUpperCase()}!</div>; }
, . TypeScript, .d.ts DefinitelyTyped , , @types/react . DefinitelyTyped, .
/// <reference lib="..." />
, , , (polyfills) — , API , ( .d.ts), API. , TypeScript lib.d.ts , --lib --target. , core-js lib.es2015.d.ts.
TypeScript 3.0 , API, , : /// <reference lib="..." />.
, Promise ES2015
, TypeScript 3.0 , lib.es2015.promise.d.ts, , Promise .
, , TypeScript , . TypeScript JavaScript , Visual Studio, Visual Studio Code TypeScript. , , , Go to Definition (« ») . TypeScript 3.0 .
, , .
import * as dependency from "./dependency"; // look at all this repetition! dependency.foo(); dependency.bar(); dependency.baz();
, , , , .
import { foo, bar, baz } from "./dependency";
, , . TypeScript 3.0 , .

TypeScript , JSX:

TypeScript — , .
,
API .
, TypeScript 3 , . , API .
unknown —
unknown — , , , .
API
- LanguageService#getSourceFile , . . #24540 .
- TypeChecker#getSymbolDisplayBuilder . . #25331 . emitter ( ) node builder.
- escapeIdentifier unescapeIdentifier . API , . , , . escapeLeadingUnderscores unescapeLeadingUnderscores, , ( «» __String string ).
- TypeChecker#getSuggestionForNonexistentProperty, TypeChecker#getSuggestionForNonexistentSymbol TypeChecker#getSuggestionForNonexistentModule , API. . #25520 .
前景展望
TypeScript . , , , DefinitelyTyped , . , .
, TypeScript ( , ). , , JavaScript. , TypeScript, .
, , , , ,
Twitter . .
, TypeScript, ! . , , TypeScript , .
!
TypeScript