可识别空值和未定义的类型
¥Null- and undefined-aware types
TypeScript 有两种特殊类型,Null 和 Undefined,它们的值分别为 null
和 undefined
。之前无法明确命名这些类型,但现在无论类型检查模式如何,null
和 undefined
都可以用作类型名称。
¥TypeScript has two special types, Null and Undefined, that have the values null
and undefined
respectively.
Previously it was not possible to explicitly name these types, but null
and undefined
may now be used as type names regardless of type checking mode.
类型检查器之前认为 null
和 undefined
可以赋值给任何类型。实际上,null
和 undefined
是每种类型的有效值,并且无法明确排除它们(因此无法检测到它们的错误使用)。
¥The type checker previously considered null
and undefined
assignable to anything.
Effectively, null
and undefined
were valid values of every type and it wasn’t possible to specifically exclude them (and therefore not possible to detect erroneous use of them).
--strictNullChecks
strictNullChecks
切换到新的严格空值检查模式。
¥strictNullChecks
switches to a new strict null checking mode.
在严格空值检查模式下,null
和 undefined
的值并非属于任何类型的定义域,只能赋值给它们自身和 any
(唯一的例外是 undefined
也可以赋值给 void
)。因此,虽然 T
和 T | undefined
在常规类型检查模式下被视为同义词(因为 undefined
被视为任何 T
的子类型),但它们在严格类型检查模式下是不同的类型,并且只有 T | undefined
允许 undefined
值。T
和 T | null
的关系也是如此。
¥In strict null checking mode, the null
and undefined
values are not in the domain of every type and are only assignable to themselves and any
(the one exception being that undefined
is also assignable to void
).
So, whereas T
and T | undefined
are considered synonymous in regular type checking mode (because undefined
is considered a subtype of any T
), they are different types in strict type checking mode, and only T | undefined
permits undefined
values. The same is true for the relationship of T
to T | null
.
示例
¥Example
ts
// Compiled with --strictNullCheckslet x: number;let y: number | undefined;let z: number | null | undefined;x = 1; // Oky = 1; // Okz = 1; // Okx = undefined; // Errory = undefined; // Okz = undefined; // Okx = null; // Errory = null; // Errorz = null; // Okx = y; // Errorx = z; // Errory = x; // Oky = z; // Errorz = x; // Okz = y; // Ok
使用前赋值检查
¥Assigned-before-use checking
在严格空检查模式下,编译器要求在每个可能的前面代码路径中,对不包含 undefined
类型的局部变量的每个引用之前都先对该变量进行赋值。
¥In strict null checking mode the compiler requires every reference to a local variable of a type that doesn’t include undefined
to be preceded by an assignment to that variable in every possible preceding code path.
示例
¥Example
ts
// Compiled with --strictNullCheckslet x: number;let y: number | null;let z: number | undefined;x; // Error, reference not preceded by assignmenty; // Error, reference not preceded by assignmentz; // Okx = 1;y = null;x; // Oky; // Ok
编译器通过执行基于控制流的类型分析来检查变量是否已明确赋值。有关此主题的更多详细信息,请参阅下文。
¥The compiler checks that variables are definitely assigned by performing control flow based type analysis. See later for further details on this topic.
可选参数和属性
¥Optional parameters and properties
可选参数和属性的类型会自动添加 undefined
,即使它们的类型注释没有明确包含 undefined
。例如,以下两种类型相同:
¥Optional parameters and properties automatically have undefined
added to their types, even when their type annotations don’t specifically include undefined
.
For example, the following two types are identical:
ts
// Compiled with --strictNullCheckstype T1 = (x?: number) => string; // x has type number | undefinedtype T2 = (x?: number | undefined) => string; // x has type number | undefined
非空和非未定义类型保护
¥Non-null and non-undefined type guards
如果对象或函数的类型包含 null
或 undefined
,则属性访问或函数调用会产生编译时错误。但是,类型保护已扩展以支持非空和非未定义检查。
¥A property access or a function call produces a compile-time error if the object or function is of a type that includes null
or undefined
.
However, type guards are extended to support non-null and non-undefined checks.
示例
¥Example
ts
// Compiled with --strictNullChecksdeclare function f(x: number): string;let x: number | null | undefined;if (x) {f(x); // Ok, type of x is number here} else {f(x); // Error, type of x is number? here}let a = x != null ? f(x) : ""; // Type of a is stringlet b = x && f(x); // Type of b is string | 0 | null | undefined
非空和非未定义的类型保护可以使用 ==
、!=
、===
或 !==
运算符与 null
或 undefined
进行比较,如 x != null
或 x === undefined
。对主题变量类型的影响准确反映了 JavaScript 语义(例如,双等号运算符无论指定了哪个值都会检查两个值,而三等号运算符仅检查指定的值)。
¥Non-null and non-undefined type guards may use the ==
, !=
, ===
, or !==
operator to compare to null
or undefined
, as in x != null
or x === undefined
.
The effects on subject variable types accurately reflect JavaScript semantics (e.g. double-equals operators check for both values no matter which one is specified whereas triple-equals only checks for the specified value).
类型保护中的点名
¥Dotted names in type guards
类型保护以前仅支持检查局部变量和参数。类型保护现在支持检查由变量或参数名称后跟一个或多个属性访问组成的 “带点的名称”。
¥Type guards previously only supported checking local variables and parameters. Type guards now support checking “dotted names” consisting of a variable or parameter name followed by one or more property accesses.
示例
¥Example
ts
interface Options {location?: {x?: number;y?: number;};}function foo(options?: Options) {if (options && options.location && options.location.x) {const x = options.location.x; // Type of x is number}}
点名称的类型保护也适用于用户定义的类型保护函数以及 typeof
和 instanceof
运算符,并且不依赖于 strictNullChecks
编译器选项。
¥Type guards for dotted names also work with user defined type guard functions and the typeof
and instanceof
operators and do not depend on the strictNullChecks
compiler option.
对点分名称的任何部分进行赋值后,其类型保护均无效。例如,在对 x
、x.y
或 x.y.z
赋值后,x.y.z
的类型保护将不起作用。
¥A type guard for a dotted name has no effect following an assignment to any part of the dotted name.
For example, a type guard for x.y.z
will have no effect following an assignment to x
, x.y
, or x.y.z
.
表达式运算符
¥Expression operators
表达式运算符允许操作数类型包含 null
和/或 undefined
,但始终会生成非空且非未定义类型的值。
¥Expression operators permit operand types to include null
and/or undefined
but always produce values of non-null and non-undefined types.
ts
// Compiled with --strictNullChecksfunction sum(a: number | null, b: number | null) {return a + b; // Produces value of type number}
&&
运算符会根据左操作数的类型,将 null
和/或 undefined
添加到右操作数的类型中;而 ||
运算符则会在生成的联合类型中,从左操作数的类型中删除 null
和 undefined
。
¥The &&
operator adds null
and/or undefined
to the type of the right operand depending on which are present in the type of the left operand, and the ||
operator removes both null
and undefined
from the type of the left operand in the resulting union type.
ts
// Compiled with --strictNullChecksinterface Entity {name: string;}let x: Entity | null;let s = x && x.name; // s is of type string | nulllet y = x || { name: "test" }; // y is of type Entity
类型扩展
¥Type widening
在严格空检查模式下,null
和 undefined
类型不会扩展为 any
。
¥The null
and undefined
types are not widened to any
in strict null checking mode.
ts
let z = null; // Type of z is null
在常规类型检查模式下,由于扩展,z
的推断类型为 any
,但在严格空检查模式下,z
的推断类型为 null
(因此,如果没有类型注解,null
是 z
的唯一可能值)。
¥In regular type checking mode the inferred type of z
is any
because of widening, but in strict null checking mode the inferred type of z
is null
(and therefore, absent a type annotation, null
is the only possible value for z
).
非空断言运算符
¥Non-null assertion operator
新的 !
后缀表达式运算符可用于在类型检查器无法断言其操作数非空且非未定义的情况下断言该操作数。具体来说,操作 x!
会生成一个 x
类型的值,但不包括 null
和 undefined
。与 <T>x
和 x as T
形式的类型断言类似,!
非空断言运算符在生成的 JavaScript 代码中会被直接删除。
¥A new !
post-fix expression operator may be used to assert that its operand is non-null and non-undefined in contexts where the type checker is unable to conclude that fact.
Specifically, the operation x!
produces a value of the type of x
with null
and undefined
excluded.
Similar to type assertions of the forms <T>x
and x as T
, the !
non-null assertion operator is simply removed in the emitted JavaScript code.
ts
// Compiled with --strictNullChecksfunction validateEntity(e?: Entity) {// Throw exception if e is null or invalid entity}function processEntity(e?: Entity) {validateEntity(e);let s = e!.name; // Assert that e is non-null and access name}
兼容性
¥Compatibility
新功能的设计使其可以在严格空值检查模式和常规类型检查模式下使用。具体来说,在常规类型检查模式下,null
和 undefined
类型会自动从联合类型中删除(因为它们是所有其他类型的子类型),并且 !
非空断言表达式运算符在常规类型检查模式下允许使用,但不起作用。因此,更新为使用可识别 null 和 undefined 类型的声明文件仍可在常规类型检查模式下使用,以实现向后兼容性。
¥The new features are designed such that they can be used in both strict null checking mode and regular type checking mode.
In particular, the null
and undefined
types are automatically erased from union types in regular type checking mode (because they are subtypes of all other types), and the !
non-null assertion expression operator is permitted but has no effect in regular type checking mode. Thus, declaration files that are updated to use null- and undefined-aware types can still be used in regular type checking mode for backwards compatibility.
实际上,严格空值检查模式要求编译中的所有文件都具备空值和未定义感知能力。
¥In practical terms, strict null checking mode requires that all files in a compilation are null- and undefined-aware.
基于控制流的类型分析
¥Control flow based type analysis
TypeScript 2.0 实现了基于控制流的局部变量和参数类型分析。以前,对类型保护执行的类型分析仅限于 if
语句和 ?:
条件表达式,不包括赋值语句和控制流结构(例如 return
和 break
语句)的效果。在 TypeScript 2.0 中,类型检查器会分析语句和表达式中所有可能的控制流,以便在任何给定位置为声明为联合类型的局部变量或参数生成最具体的类型(缩小的类型)。
¥TypeScript 2.0 implements a control flow-based type analysis for local variables and parameters.
Previously, the type analysis performed for type guards was limited to if
statements and ?:
conditional expressions and didn’t include effects of assignments and control flow constructs such as return
and break
statements.
With TypeScript 2.0, the type checker analyses all possible flows of control in statements and expressions to produce the most specific type possible (the narrowed type) at any given location for a local variable or parameter that is declared to have a union type.
示例
¥Example
ts
function foo(x: string | number | boolean) {if (typeof x === "string") {x; // type of x is string herex = 1;x; // type of x is number here}x; // type of x is number | boolean here}function bar(x: string | number) {if (typeof x === "number") {return;}x; // type of x is string here}
基于控制流的类型分析在 strictNullChecks
模式下尤为重要,因为可空类型使用联合类型表示:
¥Control flow based type analysis is particularly relevant in strictNullChecks
mode because nullable types are represented using union types:
ts
function test(x: string | null) {if (x === null) {return;}x; // type of x is string in remainder of function}
此外,在 strictNullChecks
模式下,基于控制流的类型分析包括对不允许使用 undefined
值的类型的局部变量进行明确赋值分析。
¥Furthermore, in strictNullChecks
mode, control flow based type analysis includes definite assignment analysis for local variables of types that don’t permit the value undefined
.
ts
function mumble(check: boolean) {let x: number; // Type doesn't permit undefinedx; // Error, x is undefinedif (check) {x = 1;x; // Ok}x; // Error, x is possibly undefinedx = 2;x; // Ok}
带标签的联合类型
¥Tagged union types
TypeScript 2.0 实现了对带标记(或可区分)联合类型的支持。具体来说,TS 编译器现在支持类型保护,它可以根据判别属性的测试来缩小联合类型的范围,并将该功能扩展到 switch
语句。
¥TypeScript 2.0 implements support for tagged (or discriminated) union types.
Specifically, the TS compiler now support type guards that narrow union types based on tests of a discriminant property and furthermore extend that capability to switch
statements.
示例
¥Example
ts
interface Square {kind: "square";size: number;}interface Rectangle {kind: "rectangle";width: number;height: number;}interface Circle {kind: "circle";radius: number;}type Shape = Square | Rectangle | Circle;function area(s: Shape) {// In the following switch statement, the type of s is narrowed in each case clause// according to the value of the discriminant property, thus allowing the other properties// of that variant to be accessed without a type assertion.switch (s.kind) {case "square":return s.size * s.size;case "rectangle":return s.width * s.height;case "circle":return Math.PI * s.radius * s.radius;}}function test1(s: Shape) {if (s.kind === "square") {s; // Square} else {s; // Rectangle | Circle}}function test2(s: Shape) {if (s.kind === "square" || s.kind === "rectangle") {return;}s; // Circle}
判别属性类型保护是形式为 x.p == v
、x.p === v
、x.p != v
或 x.p !== v
的表达式,其中 p
和 v
是属性以及字符串字面量类型或字符串字面量类型联合的表达式。判别属性类型保护将 x
的类型缩小到 x
的组成类型,这些类型具有判别属性 p
,并且该属性是 v
的可能值之一。
¥A discriminant property type guard is an expression of the form x.p == v
, x.p === v
, x.p != v
, or x.p !== v
, where p
and v
are a property and an expression of a string literal type or a union of string literal types.
The discriminant property type guard narrows the type of x
to those constituent types of x
that have a discriminant property p
with one of the possible values of v
.
请注意,我们目前仅支持字符串字面量类型的判别属性。我们计划稍后添加对布尔值和数字字面量类型的支持。
¥Note that we currently only support discriminant properties of string literal types. We intend to later add support for boolean and numeric literal types.
never
类型
¥The never
type
TypeScript 2.0 引入了一个新的原始类型 never
。never
类型表示永远不会出现的值的类型。具体来说,never
是永不返回的函数的返回类型,而 never
是类型保护下永不为真的变量的类型。
¥TypeScript 2.0 introduces a new primitive type never
.
The never
type represents the type of values that never occur.
Specifically, never
is the return type for functions that never return and never
is the type of variables under type guards that are never true.
never
类型具有以下特点:
¥The never
type has the following characteristics:
-
never
是所有类型的子类型,并且可以赋值给所有类型。¥
never
is a subtype of and assignable to every type. -
没有任何类型是
never
的子类型或可赋值给never
(never
本身除外)。¥No type is a subtype of or assignable to
never
(exceptnever
itself). -
在没有返回类型注释的函数表达式或箭头函数中,如果函数没有
return
语句,或者只有带有never
类型表达式的return
语句,并且函数的终点不可到达(由控制流分析确定),则该函数的推断返回类型为never
。¥In a function expression or arrow function with no return type annotation, if the function has no
return
statements, or onlyreturn
statements with expressions of typenever
, and if the end point of the function is not reachable (as determined by control flow analysis), the inferred return type for the function isnever
. -
在具有显式
never
返回类型注释的函数中,所有return
语句(如果有)必须包含never
类型的表达式,并且函数的终点必须是不可访问的。¥In a function with an explicit
never
return type annotation, allreturn
statements (if any) must have expressions of typenever
and the end point of the function must not be reachable.
由于 never
是所有类型的子类型,因此只要返回的是其他类型,它总是会在联合类型中被省略,并且在函数返回类型推断中也会被忽略。
¥Because never
is a subtype of every type, it is always omitted from union types and it is ignored in function return type inference as long as there are other types being returned.
一些返回 never
的函数示例:
¥Some examples of functions returning never
:
ts
// Function returning never must have unreachable end pointfunction error(message: string): never {throw new Error(message);}// Inferred return type is neverfunction fail() {return error("Something failed");}// Function returning never must have unreachable end pointfunction infiniteLoop(): never {while (true) {}}
一些返回 never
的函数使用示例:
¥Some examples of use of functions returning never
:
ts
// Inferred return type is numberfunction move1(direction: "up" | "down") {switch (direction) {case "up":return 1;case "down":return -1;}return error("Should never get here");}// Inferred return type is numberfunction move2(direction: "up" | "down") {return direction === "up"? 1: direction === "down"? -1: error("Should never get here");}// Inferred return type is Tfunction check<T>(x: T | undefined) {return x || error("Undefined value");}
由于 never
可分配给所有类型,因此当需要回调返回更具体的类型时,可以使用返回 never
的函数:
¥Because never
is assignable to every type, a function returning never
can be used when a callback returning a more specific type is required:
ts
function test(cb: () => string) {let s = cb();return s;}test(() => "hello");test(() => fail());test(() => {throw new Error();});
只读属性和索引签名
¥Read-only properties and index signatures
现在可以使用 readonly
修饰符声明属性或索引签名。
¥A property or index signature can now be declared with the readonly
modifier.
只读属性可以具有初始化函数,并且可以在同一类声明中的构造函数中赋值,但除此之外,不允许对只读属性进行赋值。
¥Read-only properties may have initializers and may be assigned to in constructors within the same class declaration, but otherwise assignments to read-only properties are disallowed.
此外,实体在以下几种情况下是隐式只读的:
¥In addition, entities are implicitly read-only in several situations:
-
使用
get
访问器声明而未使用set
访问器的属性将被视为只读。¥A property declared with a
get
accessor and noset
accessor is considered read-only. -
在枚举对象类型中,枚举成员被视为只读属性。
¥In the type of an enum object, enum members are considered read-only properties.
-
在模块对象类型中,导出的
const
变量被视为只读属性。¥In the type of a module object, exported
const
variables are considered read-only properties. -
在
import
语句中声明的实体被视为只读。¥An entity declared in an
import
statement is considered read-only. -
通过 ES2015 命名空间导入访问的实体被视为只读(例如,当
foo
声明为import * as foo from "foo"
时,foo.x
为只读)。¥An entity accessed through an ES2015 namespace import is considered read-only (e.g.
foo.x
is read-only whenfoo
is declared asimport * as foo from "foo"
).
示例
¥Example
ts
interface Point {readonly x: number;readonly y: number;}var p1: Point = { x: 10, y: 20 };p1.x = 5; // Error, p1.x is read-onlyvar p2 = { x: 1, y: 1 };var p3: Point = p2; // Ok, read-only alias for p2p3.x = 5; // Error, p3.x is read-onlyp2.x = 5; // Ok, but also changes p3.x because of aliasing
ts
class Foo {readonly a = 1;readonly b: string;constructor() {this.b = "hello"; // Assignment permitted in constructor}}
ts
let a: Array<number> = [0, 1, 2, 3, 4];let b: ReadonlyArray<number> = a;b[5] = 5; // Error, elements are read-onlyb.push(5); // Error, no push method (because it mutates array)b.length = 3; // Error, length is read-onlya = b; // Error, mutating methods are missing
为函数指定 this
的类型
¥Specifying the type of this
for functions
在类或接口中指定 this
的类型后,函数和方法现在可以声明它们期望的 this
类型。
¥Following up on specifying the type of this
in a class or an interface, functions and methods can now declare the type of this
they expect.
默认情况下,函数内部 this
的类型为 any
。从 TypeScript 2.0 开始,你可以提供显式的 this
参数。this
参数是伪参数,位于函数参数列表的首位:
¥By default the type of this
inside a function is any
.
Starting with TypeScript 2.0, you can provide an explicit this
parameter.
this
parameters are fake parameters that come first in the parameter list of a function:
ts
function f(this: void) {// make sure `this` is unusable in this standalone function}
回调函数中的 this
参数
¥this
parameters in callbacks
库也可以使用 this
参数来声明回调函数的调用方式。
¥Libraries can also use this
parameters to declare how callbacks will be invoked.
示例
¥Example
ts
interface UIElement {addClickListener(onclick: (this: void, e: Event) => void): void;}
this: void
意味着 addClickListener
期望 onclick
是一个不需要 this
类型的函数。
¥this: void
means that addClickListener
expects onclick
to be a function that does not require a this
type.
现在,如果你使用 this
注释调用代码:
¥Now if you annotate calling code with this
:
ts
class Handler {info: string;onClickBad(this: Handler, e: Event) {// oops, used this here. using this callback would crash at runtimethis.info = e.message;}}let h = new Handler();uiElement.addClickListener(h.onClickBad); // error!
--noImplicitThis
TypeScript 2.0 中还添加了一个新标志,用于标记所有在没有显式类型注释的函数中使用 this
的情况。
¥A new flag is also added in TypeScript 2.0 to flag all uses of this
in functions without an explicit type annotation.
tsconfig.json
中的 Glob 支持
¥Glob support in tsconfig.json
全局变量支持现已推出!!最受期待的功能之一 已支持 Glob。
¥Glob support is here!! Glob support has been one of the most requested features.
类似 Glob 的文件模式由两个属性 include
和 exclude
支持。
¥Glob-like file patterns are supported by two properties include
and exclude
.
示例
¥Example
{" ": {" ": "commonjs"," ": true," ": true," ": true," ": "../../built/local/tsc.js"," ": true}," ": ["src/**/*"]," ": ["node_modules", "**/*.spec.ts"]}
支持的全局通配符为:
¥The supported glob wildcards are:
-
*
匹配零个或多个字符(不包括目录分隔符)¥
*
matches zero or more characters (excluding directory separators) -
?
匹配任何一个字符(不包括目录分隔符)¥
?
matches any one character (excluding directory separators) -
**/
递归匹配任何子目录。¥
**/
recursively matches any subdirectory
如果 glob 模式的某个部分仅包含 *
或 .*
,则仅包含支持扩展名的文件(例如,默认情况下包含 .ts
、.tsx
和 .d.ts
,如果 allowJs
设置为 true,则包含 .js
和 .jsx
)。
¥If a segment of a glob pattern includes only *
or .*
, then only files with supported extensions are included (e.g. .ts
, .tsx
, and .d.ts
by default with .js
and .jsx
if allowJs
is set to true).
如果 files
和 include
均未指定,编译器默认包含包含目录及其子目录中的所有 TypeScript(.ts
、.d.ts
和 .tsx
)文件,但使用 exclude
属性排除的文件除外。如果 allowJs
设置为 true,JS 文件(.js
和 .jsx
)也会被包含。
¥If the files
and include
are both left unspecified, the compiler defaults to including all TypeScript (.ts
, .d.ts
and .tsx
) files in the containing directory and subdirectories except those excluded using the exclude
property. JS files (.js
and .jsx
) are also included if allowJs
is set to true.
如果指定了 files
或 include
属性,编译器将包含这两个属性所包含文件的并集。使用 outDir
编译器选项指定的目录中的文件始终会被排除,除非通过 files
属性明确包含(即使指定了 exclude
属性)。
¥If the files
or include
properties are specified, the compiler will instead include the union of the files included by those two properties.
Files in the directory specified using the outDir
compiler option are always excluded unless explicitly included via the files
property (even when the exclude
property is specified).
使用 include
包含的文件可以使用 exclude
属性进行过滤。但是,无论 exclude
是什么,明确使用 files
属性包含的文件都会被包含。如果未指定,exclude
属性默认排除 node_modules
、bower_components
和 jspm_packages
目录。
¥Files included using include
can be filtered using the exclude
property.
However, files included explicitly using the files
property are always included regardless of exclude
.
The exclude
property defaults to excluding the node_modules
, bower_components
, and jspm_packages
directories when not specified.
模块解析增强功能:BaseUrl、路径映射、rootDirs 和跟踪
¥Module resolution enhancements: BaseUrl, Path mapping, rootDirs and tracing
TypeScript 2.0 提供了一组额外的模块解析选项,用于告知编译器在哪里可以找到给定模块的声明。
¥TypeScript 2.0 provides a set of additional module resolution knops to inform the compiler where to find declarations for a given module.
有关更多详细信息,请参阅 模块解析 文档。
¥See Module Resolution documentation for more details.
基本 URL
¥Base URL
在使用 AMD 模块加载器的应用中,使用 baseUrl
是一种常见做法,在应用中,模块在运行时被 “deployed” 到单个文件夹。所有带有裸说明符名称的模块导入都假定为相对于 baseUrl
。
¥Using a baseUrl
is a common practice in applications using AMD module loaders where modules are “deployed” to a single folder at run-time.
All module imports with bare specifier names are assumed to be relative to the baseUrl
.
示例
¥Example
{" ": {" ": "./modules"}}
现在,导入到 "moduleA"
的内容将在 ./modules/moduleA
中查找。
¥Now imports to "moduleA"
would be looked up in ./modules/moduleA
ts
import A from "moduleA";
路径映射
¥Path mapping
有时模块并非直接位于 baseUrl 下。加载器使用映射配置在运行时将模块名称映射到文件,请参阅 RequireJs 文档 和 SystemJS 文档。
¥Sometimes modules are not directly located under baseUrl. Loaders use a mapping configuration to map module names to files at run-time, see RequireJs documentation and SystemJS documentation.
TypeScript 编译器支持在 tsconfig.json
文件中使用 paths
属性声明此类映射。
¥The TypeScript compiler supports the declaration of such mappings using paths
property in tsconfig.json
files.
示例
¥Example
例如,导入模块 "jquery"
将在运行时转换为 "node_modules/jquery/dist/jquery.slim.min.js"
。
¥For instance, an import to a module "jquery"
would be translated at runtime to "node_modules/jquery/dist/jquery.slim.min.js"
.
{" ": {" ": "./node_modules"," ": {"jquery": ["jquery/dist/jquery.slim.min"]}}
使用 paths
还允许更复杂的映射,包括多个回退位置。考虑一个项目配置,其中只有部分模块在一个位置可用,其余模块在另一个位置可用。
¥Using paths
also allows for more sophisticated mappings including multiple fall back locations.
Consider a project configuration where only some modules are available in one location, and the rest are in another.
带有 rootDirs
¥Virtual Directories with rootDirs
使用 ‘rootDirs’,你可以告知编译器构成此 “virtual” 目录的根目录;因此,编译器可以解析这些 “virtual” 目录中的相对模块导入,就像它们合并到一个目录中一样。
¥Using ‘rootDirs’, you can inform the compiler of the roots making up this “virtual” directory; and thus the compiler can resolve relative modules imports within these “virtual” directories as if they were merged together in one directory.
示例
¥Example
给定此项目结构:
¥Given this project structure:
src └── views └── view1.ts (imports './template1') └── view2.ts generated └── templates └── views └── template1.ts (imports './view2')
构建步骤会将 /src/views
和 /generated/templates/views
中的文件复制到输出中的同一目录中。在运行时,视图可以预期其模板与其相邻,因此应该使用相对名称 "./template"
来导入它。
¥A build step will copy the files in /src/views
and /generated/templates/views
to the same directory in the output.
At run-time, a view can expect its template to exist next to it, and thus should import it using a relative name as "./template"
.
rootDirs
指定一个根列表,其内容预计在运行时合并。按照我们的示例,tsconfig.json
文件应该如下所示:
¥rootDirs
specify a list of roots whose contents are expected to merge at run-time.
So following our example, the tsconfig.json
file should look like:
{" ": {" ": ["src/views", "generated/templates/views"]}}
跟踪模块解析
¥Tracing module resolution
traceResolution
提供了一种便捷的方法来理解编译器是如何解析模块的。
¥traceResolution
offers a handy way to understand how modules have been resolved by the compiler.
shell
tsc --traceResolution
环境模块声明简写
¥Shorthand ambient module declarations
如果你不想在使用新模块前花时间编写声明,现在只需使用简写声明即可快速上手。
¥If you don’t want to take the time to write out declarations before using a new module, you can now just use a shorthand declaration to get started quickly.
declarations.d.ts
ts
declare module "hot-new-module";
所有从简写模块导入的函数都将具有 any 类型。
¥All imports from a shorthand module will have the any type.
ts
import x, { y } from "hot-new-module";x(y);
模块名称中的通配符
¥Wildcard character in module names
使用模块加载器扩展(例如 AMD 或 SystemJS)导入非代码资源以前并不容易;以前必须为每个资源定义一个环境模块声明。
¥Importing non-code resources using module loaders extension (e.g. AMD or SystemJS) has not been easy before; previously an ambient module declaration had to be defined for each resource.
TypeScript 2.0 支持使用通配符 (*
) 来声明模块名称的 “family”;这样,扩展只需要声明一次,而不是每个资源都需要声明一次。
¥TypeScript 2.0 supports the use of the wildcard character (*
) to declare a “family” of module names;
this way, a declaration is only required once for an extension, and not for every resource.
示例
¥Example
ts
declare module "*!text" {const content: string;export default content;}// Some do it the other way around.declare module "json!*" {const value: any;export default value;}
现在你可以导入与 "*!text"
或 "json!*"
匹配的内容。
¥Now you can import things that match "*!text"
or "json!*"
.
ts
import fileContent from "./xyz.txt!text";import data from "json!http://example.com/data.json";console.log(data, fileContent);
从无类型代码库迁移时,通配符模块名称会更加有用。结合简写环境模块声明,可以轻松地将一组模块声明为 any
。
¥Wildcard module names can be even more useful when migrating from an un-typed code base.
Combined with Shorthand ambient module declarations, a set of modules can be easily declared as any
.
示例
¥Example
ts
declare module "myLibrary/*";
编译器将认为对 myLibrary
下任何模块的所有导入都具有 any
类型;因此,关闭对这些模块的形状或类型的任何检查。
¥All imports to any module under myLibrary
would be considered to have the type any
by the compiler;
thus, shutting down any checking on the shapes or types of these modules.
ts
import { readFile } from "myLibrary/fileSystem/readFile`;readFile(); // readFile is 'any'
支持 UMD 模块定义
¥Support for UMD module definitions
一些库被设计为可在多个模块加载器中使用,或者无需模块加载(全局变量)。这些被称为 UMD 或 同构 模块。这些库可以通过导入或全局变量访问。
¥Some libraries are designed to be used in many module loaders, or with no module loading (global variables). These are known as UMD or Isomorphic modules. These libraries can be accessed through either an import or a global variable.
例如:
¥For example:
math-lib.d.ts
ts
export const isPrime(x: number): boolean;export as namespace mathLib;
该库随后可在模块内导入使用:
¥The library can then be used as an import within modules:
ts
import { isPrime } from "math-lib";isPrime(2);mathLib.isPrime(2); // ERROR: can't use the global definition from inside a module
它也可以用作全局变量,但只能在脚本内部使用。(脚本是没有导入或导出操作的文件。)
¥It can also be used as a global variable, but only inside of a script. (A script is a file with no imports or exports.)
ts
mathLib.isPrime(2);
可选类属性
¥Optional class properties
现在可以在类中声明可选属性和方法,类似于接口中已经允许的操作。
¥Optional properties and methods can now be declared in classes, similar to what is already permitted in interfaces.
示例
¥Example
ts
class Bar {a: number;b?: number;f() {return 1;}g?(): number; // Body of optional method can be omittedh?() {return 2;}}
在 strictNullChecks
模式下编译时,可选属性和方法的类型会自动包含 undefined
。因此,上面的 b
属性的类型为 number | undefined
,而上面的 g
方法的类型为 (() => number) | undefined
。类型保护可用于剥离类型的 undefined
部分:
¥When compiled in strictNullChecks
mode, optional properties and methods automatically have undefined
included in their type. Thus, the b
property above is of type number | undefined
and the g
method above is of type (() => number) | undefined
.
Type guards can be used to strip away the undefined
part of the type:
ts
function test(x: Bar) {x.a; // numberx.b; // number | undefinedx.f; // () => numberx.g; // (() => number) | undefinedlet f1 = x.f(); // numberlet g1 = x.g && x.g(); // number | undefinedlet g2 = x.g ? x.g() : 0; // number}
私有和受保护的构造函数
¥Private and Protected Constructors
类构造函数可以标记为 private
或 protected
。具有私有构造函数的类不能在类体外实例化,也不能扩展。具有受保护构造函数的类不能在类体外实例化,但可以扩展。
¥A class constructor may be marked private
or protected
.
A class with a private constructor cannot be instantiated outside the class body, and cannot be extended.
A class with a protected constructor cannot be instantiated outside the class body, but can be extended.
示例
¥Example
ts
class Singleton {private static instance: Singleton;private constructor() {}static getInstance() {if (!Singleton.instance) {Singleton.instance = new Singleton();}return Singleton.instance;}}let e = new Singleton(); // Error: constructor of 'Singleton' is private.let v = Singleton.getInstance();
抽象属性和访问器
¥Abstract properties and accessors
抽象类可以声明抽象属性和/或访问器。任何子类都需要声明抽象属性或将其标记为抽象。抽象属性不能有初始化器。抽象访问器不能有主体。
¥An abstract class can declare abstract properties and/or accessors. Any sub class will need to declare the abstract properties or be marked as abstract. Abstract properties cannot have an initializer. Abstract accessors cannot have bodies.
示例
¥Example
ts
abstract class Base {abstract name: string;abstract get value();abstract set value(v: number);}class Derived extends Base {name = "derived";value = 1;}
隐式索引签名
¥Implicit index signatures
如果对象字面量中所有已知属性都可以赋值给具有索引签名的类型,则对象字面量类型现在可以赋值给该索引签名的类型。这样就可以将一个用对象字面量初始化的变量作为参数传递给需要映射或字典的函数:
¥An object literal type is now assignable to a type with an index signature if all known properties in the object literal are assignable to that index signature. This makes it possible to pass a variable that was initialized with an object literal as parameter to a function that expects a map or dictionary:
ts
function httpService(path: string, headers: { [x: string]: string }) {}const headers = {"Content-Type": "application/x-www-form-urlencoded",};httpService("", { "Content-Type": "application/x-www-form-urlencoded" }); // OkhttpService("", headers); // Now ok, previously wasn't
在 中包含内置类型声明 --lib
¥Including built-in type declarations with --lib
ES6/ES2015 内置 API 声明仅限于 target: ES6
。输入 lib
;使用 lib
,你可以指定内置 API 声明组列表,你可以选择将其包含在项目中。例如,如果你希望运行时支持 Map
、Set
和 Promise
(例如当今大多数常用浏览器),则只需包含 --lib es2015.collection,es2015.promise
。同样,你可以排除不想包含在项目中的声明,例如,如果你正在使用 --lib es5,es6
开发 Node 项目,则可以排除 DOM。
¥Getting to ES6/ES2015 built-in API declarations were only limited to target: ES6
.
Enter lib
; with lib
you can specify a list of built-in API declaration groups that you can choose to include in your project.
For instance, if you expect your runtime to have support for Map
, Set
and Promise
(e.g. most evergreen browsers today), just include --lib es2015.collection,es2015.promise
.
Similarly you can exclude declarations you do not want to include in your project, e.g. DOM if you are working on a node project using --lib es5,es6
.
以下是可用 API 组列表:
¥Here is a list of available API groups:
-
dom
-
webworker
-
es5
-
es6 / es2015
-
es2015.core
-
es2015.collection
-
es2015.iterable
-
es2015.promise
-
es2015.proxy
-
es2015.reflect
-
es2015.generator
-
es2015.symbol
-
es2015.symbol.wellknown
-
es2016
-
es2016.array.include
-
es2017
-
es2017.object
-
es2017.sharedmemory
-
scripthost
示例
¥Example
bash
tsc --target es5 --lib es5,es2015.promise
"compilerOptions": {" ": ["es5", "es2015.promise"]}
使用 --noUnusedParameters
和 --noUnusedLocals
标记未使用的声明
¥Flag unused declarations with --noUnusedParameters
and --noUnusedLocals
TypeScript 2.0 增加了两个新标志,可帮助你维护干净的代码库。noUnusedParameters
会标记任何未使用的函数或方法参数错误。noUnusedLocals
会标记任何未使用的本地(未导出)声明,例如变量、函数、类、导入等……此外,在 noUnusedLocals
下,类中未使用的私有成员将被标记为错误。
¥TypeScript 2.0 has two new flags to help you maintain a clean code base.
noUnusedParameters
flags any unused function or method parameters errors.
noUnusedLocals
flags any unused local (un-exported) declaration like variables, functions, classes, imports, etc…
Also, unused private members of a class would be flagged as errors under noUnusedLocals
.
示例
¥Example
ts
import B, { readFile } from "./b";// ^ Error: `B` declared but never usedreadFile();export function write(message: string, args: string[]) {// ^^^^ Error: 'arg' declared but never used.console.log(message);}
名称以 _
开头的参数声明不受未使用参数检查的影响。例如。:
¥Parameters declaration with names starting with _
are exempt from the unused parameter checking.
e.g.:
ts
function returnNull(_a) {// OKreturn null;}
模块标识符允许 .js
扩展
¥Module identifiers allow for .js
extension
在 TypeScript 2.0 之前,模块标识符始终被假定为无扩展名;例如,给定一个导入为 import d from "./moduleA.js"
的语句,编译器会在 ./moduleA.js.ts
或 ./moduleA.js.d.ts
中查找 "moduleA.js"
的定义。这使得使用像 SystemJS 这样在其模块标识符中需要 URI 的打包/加载工具变得困难。
¥Before TypeScript 2.0, a module identifier was always assumed to be extension-less;
for instance, given an import as import d from "./moduleA.js"
, the compiler looked up the definition of "moduleA.js"
in ./moduleA.js.ts
or ./moduleA.js.d.ts
.
This made it hard to use bundling/loading tools like SystemJS that expect URI’s in their module identifier.
在 TypeScript 2.0 中,编译器将在 ./moduleA.ts
或 ./moduleA.d.t
中查找 "moduleA.js"
的定义。
¥With TypeScript 2.0, the compiler will look up definition of "moduleA.js"
in ./moduleA.ts
or ./moduleA.d.t
.
使用 ‘module: 支持 ‘目标:es5’es6’
¥Support ‘target : es5’ with ‘module: es6’
之前标记为无效的标志组合:target: es5
和 ‘module:es6’ 现已支持。这应该有助于使用基于 ES2015 的摇树优化器 (例如 rollup)。
¥Previously flagged as an invalid flag combination, target: es5
and ‘module: es6’ is now supported.
This should facilitate using ES2015-based tree shakers like rollup.
函数形参和实参列表中的尾随逗号
¥Trailing commas in function parameter and argument lists
现在允许在函数参数和实参列表中使用尾随逗号。这是一个 ECMAScript 第三阶段提案 的实现,它向下兼容有效的 ES3/ES5/ES6。
¥Trailing comma in function parameter and argument lists are now allowed. This is an implementation for a Stage-3 ECMAScript proposal that emits down to valid ES3/ES5/ES6.
示例
¥Example
ts
function foo(bar: Bar,baz: Baz // trailing commas are OK in parameter lists) {// Implementation...}foo(bar,baz // and in argument lists);
新的 --skipLibCheck
¥New --skipLibCheck
TypeScript 2.0 添加了一个新的 skipLibCheck
编译器选项,该选项可跳过声明文件(扩展名为 .d.ts
的文件)的类型检查。当程序包含大型声明文件时,编译器会花费大量时间对已知不包含错误的声明进行类型检查,而跳过声明文件的类型检查可能会显著缩短编译时间。
¥TypeScript 2.0 adds a new skipLibCheck
compiler option that causes type checking of declaration files (files with extension .d.ts
) to be skipped.
When a program includes large declaration files, the compiler spends a lot of time type checking declarations that are already known to not contain errors, and compile times may be significantly shortened by skipping declaration file type checks.
由于一个文件中的声明可能会影响其他文件中的类型检查,因此在指定 skipLibCheck
时可能无法检测到某些错误。例如,如果非声明文件扩充了声明文件中声明的类型,则可能导致错误,这些错误仅在检查声明文件时才会报告。但是,在实践中,这种情况很少见。
¥Since declarations in one file can affect type checking in other files, some errors may not be detected when skipLibCheck
is specified.
For example, if a non-declaration file augments a type declared in a declaration file, errors may result that are only reported when the declaration file is checked.
However, in practice such situations are rare.
允许跨声明使用重复的标识符
¥Allow duplicate identifiers across declarations
这一直是重复定义错误的常见原因之一。多个声明文件在接口上定义相同的成员。
¥This has been one common source of duplicate definition errors. Multiple declaration files defining the same members on interfaces.
TypeScript 2.0 放宽了此限制,允许跨块使用重复的标识符,只要它们具有相同的类型。
¥TypeScript 2.0 relaxes this constraint and allows duplicate identifiers across blocks, as long as they have identical types.
在同一个块中仍然不允许重复定义。
¥Within the same block duplicate definitions are still disallowed.
示例
¥Example
ts
interface Error {stack?: string;}interface Error {code?: string;path?: string;stack?: string; // OK}
新的 --declarationDir
¥New --declarationDir
declarationDir
允许在与 JavaScript 文件不同的位置生成声明文件。
¥declarationDir
allows for generating declaration files in a different location than JavaScript files.