项目引用
¥Project References
TypeScript 3.0 引入了项目引用的新概念。项目引用允许 TypeScript 项目依赖于其他 TypeScript 项目。 - 具体来说,允许 tsconfig.json
文件引用其他 tsconfig.json
文件。指定这些依赖可以更轻松地将代码拆分为更小的项目,因为它为 TypeScript(及其相关工具)提供了一种理解构建顺序和输出结构的方法。
¥TypeScript 3.0 introduces a new concept of project references. Project references allow TypeScript projects to depend on other TypeScript projects - specifically, allowing tsconfig.json
files to reference other tsconfig.json
files. Specifying these dependencies makes it easier to split your code into smaller projects, since it gives TypeScript (and tools around it) a way to understand build ordering and output structure.
TypeScript 3.0 还为 tsc 引入了一种新模式,即 --build
标志,它与项目引用协同工作,以加快 TypeScript 构建速度。
¥TypeScript 3.0 also introduces a new mode for tsc, the --build
flag, that works hand-in-hand with project references to enable faster TypeScript builds.
有关更多文档,请参阅 项目参考手册页面。
¥See Project References handbook page for more documentation.
剩余参数和扩展表达式中的元组
¥Tuples in rest parameters and spread expressions
TypeScript 3.0 增加了对多项新功能的支持,可以将函数参数列表作为元组类型进行交互。TypeScript 3.0 增加了对以下内容的支持:
¥TypeScript 3.0 adds support to multiple new capabilities to interact with function parameter lists as tuple types. TypeScript 3.0 adds support for:
-
¥Expansion of rest parameters with tuple types into discrete parameters.
-
¥Expansion of spread expressions with tuple types into discrete arguments.
-
¥Generic rest parameters and corresponding inference of tuple types.
借助这些特性,我们可以将一些高阶函数强类型化,从而转换函数及其参数列表。
¥With these features it becomes possible to strongly type a number of higher-order functions that transform functions and their parameter lists.
元组类型的剩余参数
¥Rest parameters with tuple types
当剩余参数具有元组类型时,元组类型将扩展为离散参数序列。例如,以下两个声明是等效的:
¥When a rest parameter has a tuple type, the tuple type is expanded into a sequence of discrete parameters. For example the following two declarations are equivalent:
ts
declare function foo(...args: [number, string, boolean]): void;
ts
declare function foo(args_0: number, args_1: string, args_2: boolean): void;
元组类型的展开表达式
¥Spread expressions with tuple types
当函数调用包含元组类型的展开表达式作为最后一个参数时,该展开表达式对应于元组元素类型的离散参数序列。
¥When a function call includes a spread expression of a tuple type as the last argument, the spread expression corresponds to a sequence of discrete arguments of the tuple element types.
因此,以下调用是等效的:
¥Thus, the following calls are equivalent:
ts
const args: [number, string, boolean] = [42, "hello", true];foo(42, "hello", true);foo(args[0], args[1], args[2]);foo(...args);
泛型剩余参数
¥Generic rest parameters
剩余参数允许具有受限于数组类型的泛型,并且类型推断可以推断此类泛型剩余参数的元组类型。这支持高阶捕获和扩展部分参数列表:
¥A rest parameter is permitted to have a generic type that is constrained to an array type, and type inference can infer tuple types for such generic rest parameters. This enables higher-order capturing and spreading of partial parameter lists:
示例
¥Example
ts
declare function bind<T, U extends any[], V>(f: (x: T, ...args: U) => V,x: T): (...args: U) => V;declare function f3(x: number, y: string, z: boolean): void;const f2 = bind(f3, 42); // (y: string, z: boolean) => voidconst f1 = bind(f2, "hello"); // (z: boolean) => voidconst f0 = bind(f1, true); // () => voidf3(42, "hello", true);f2("hello", true);f1(true);f0();
在上面 f2
的声明中,类型推断分别将 T
、U
和 V
推断为 number
、[string, boolean]
和 void
类型。
¥In the declaration of f2
above, type inference infers types number
, [string, boolean]
and void
for T
, U
and V
respectively.
请注意,当从参数序列推断出元组类型,然后将其扩展为参数列表时(例如 U
的情况),扩展中使用原始参数名称(但是,这些名称没有语义含义,并且无法以其他方式观察到)。
¥Note that when a tuple type is inferred from a sequence of parameters and later expanded into a parameter list, as is the case for U
, the original parameter names are used in the expansion (however, the names have no semantic meaning and are not otherwise observable).
元组类型中的可选元素
¥Optional elements in tuple types
元组类型现在允许在元素类型上使用 ?
后缀来指示该元素是可选的:
¥Tuple types now permit a ?
postfix on element types to indicate that the element is optional:
示例
¥Example
ts
let t: [number, string?, boolean?];t = [42, "hello", true];t = [42, "hello"];t = [42];
在 strictNullChecks
模式下,?
修饰符会自动在元素类型中包含 undefined
,类似于可选参数。
¥In strictNullChecks
mode, a ?
modifier automatically includes undefined
in the element type, similar to optional parameters.
如果元组类型带有后缀 ?
修饰符,并且其右侧的所有元素也都带有 ?
修饰符,则允许省略该元素。
¥A tuple type permits an element to be omitted if it has a postfix ?
modifier on its type and all elements to the right of it also have ?
modifiers.
当推断剩余参数的元组类型时,源中的可选参数将成为推断类型中的可选元组元素。
¥When tuple types are inferred for rest parameters, optional parameters in the source become optional tuple elements in the inferred type.
具有可选元素的元组类型的 length
属性是表示可能长度的数字字面量类型的并集。例如,元组类型 [number, string?, boolean?]
中 length
属性的类型为 1 | 2 | 3
。
¥The length
property of a tuple type with optional elements is a union of numeric literal types representing the possible lengths.
For example, the type of the length
property in the tuple type [number, string?, boolean?]
is 1 | 2 | 3
.
元组类型中的剩余元素
¥Rest elements in tuple types
元组类型的最后一个元素可以是 ...X
形式的剩余元素,其中 X
是数组类型。剩余元素表示元组类型是开放式的,可以包含零个或多个数组元素类型的附加元素。例如,[number, ...string[]]
表示包含一个 number
元素后跟任意数量的 string
元素的元组。
¥The last element of a tuple type can be a rest element of the form ...X
, where X
is an array type.
A rest element indicates that the tuple type is open-ended and may have zero or more additional elements of the array element type.
For example, [number, ...string[]]
means tuples with a number
element followed by any number of string
elements.
示例
¥Example
ts
function tuple<T extends any[]>(...args: T): T {return args;}const numbers: number[] = getArrayOfNumbers();const t1 = tuple("foo", 1, true); // [string, number, boolean]const t2 = tuple("bar", ...numbers); // [string, ...number[]]
带有剩余元素的元组类型的 length
属性的类型为 number
。
¥The type of the length
property of a tuple type with a rest element is number
.
新的 unknown
顶层类型
¥New unknown
top type
TypeScript 3.0 引入了一个新的顶层类型 unknown
。unknown
是 any
的类型安全对应物。任何值都可以赋值给 unknown
,但 unknown
只能赋值给其自身和 any
,除非进行类型断言或基于控制流的收缩。同样,如果没有先断言或缩小到更具体的类型,则不允许对 unknown
进行任何操作。
¥TypeScript 3.0 introduces a new top type unknown
.
unknown
is the type-safe counterpart of any
.
Anything is assignable to unknown
, but unknown
isn’t assignable to anything but itself and any
without a type assertion or a control flow based narrowing.
Likewise, no operations are permitted on an unknown
without first asserting or narrowing to a more specific type.
示例
¥Example
ts
// In an intersection everything absorbs unknowntype T00 = unknown & null; // nulltype T01 = unknown & undefined; // undefinedtype T02 = unknown & null & undefined; // null & undefined (which becomes never)type T03 = unknown & string; // stringtype T04 = unknown & string[]; // string[]type T05 = unknown & unknown; // unknowntype T06 = unknown & any; // any// In a union an unknown absorbs everythingtype T10 = unknown | null; // unknowntype T11 = unknown | undefined; // unknowntype T12 = unknown | null | undefined; // unknowntype T13 = unknown | string; // unknowntype T14 = unknown | string[]; // unknowntype T15 = unknown | unknown; // unknowntype T16 = unknown | any; // any// Type variable and unknown in union and intersectiontype T20<T> = T & {}; // T & {}type T21<T> = T | {}; // T | {}type T22<T> = T & unknown; // Ttype T23<T> = T | unknown; // unknown// unknown in conditional typestype T30<T> = unknown extends T ? true : false; // Deferredtype T31<T> = T extends unknown ? true : false; // Deferred (so it distributes)type T32<T> = never extends T ? true : false; // truetype T33<T> = T extends never ? true : false; // Deferred// keyof unknowntype T40 = keyof any; // string | number | symboltype T41 = keyof unknown; // never// Only equality operators are allowed with unknownfunction f10(x: unknown) {x == 5;x !== 10;x >= 0; // Errorx + 1; // Errorx * 2; // Error-x; // Error+x; // Error}// No property accesses, element accesses, or function callsfunction f11(x: unknown) {x.foo; // Errorx[5]; // Errorx(); // Errornew x(); // Error}// typeof, instanceof, and user defined type predicatesdeclare function isFunction(x: unknown): x is Function;function f20(x: unknown) {if (typeof x === "string" || typeof x === "number") {x; // string | number}if (x instanceof Error) {x; // Error}if (isFunction(x)) {x; // Function}}// Homomorphic mapped type over unknowntype T50<T> = { [P in keyof T]: number };type T51 = T50<any>; // { [x: string]: number }type T52 = T50<unknown>; // {}// Anything is assignable to unknownfunction f21<T>(pAny: any, pNever: never, pT: T) {let x: unknown;x = 123;x = "hello";x = [1, 2, 3];x = new Error();x = x;x = pAny;x = pNever;x = pT;}// unknown assignable only to itself and anyfunction f22(x: unknown) {let v1: any = x;let v2: unknown = x;let v3: object = x; // Errorlet v4: string = x; // Errorlet v5: string[] = x; // Errorlet v6: {} = x; // Errorlet v7: {} | null | undefined = x; // Error}// Type parameter 'T extends unknown' not related to objectfunction f23<T extends unknown>(x: T) {let y: object = x; // Error}// Anything but primitive assignable to { [x: string]: unknown }function f24(x: { [x: string]: unknown }) {x = {};x = { a: 5 };x = [1, 2, 3];x = 123; // Error}// Locals of type unknown always considered initializedfunction f25() {let x: unknown;let y = x;}// Spread of unknown causes result to be unknownfunction f26(x: {}, y: unknown, z: any) {let o1 = { a: 42, ...x }; // { a: number }let o2 = { a: 42, ...x, ...y }; // unknownlet o3 = { a: 42, ...x, ...y, ...z }; // any}// Functions with unknown return type don't need return expressionsfunction f27(): unknown {}// Rest type cannot be created from unknownfunction f28(x: unknown) {let { ...a } = x; // Error}// Class properties of type unknown don't need definite assignmentclass C1 {a: string; // Errorb: unknown;c: any;}
支持在 JSX 中使用 defaultProps
¥Support for defaultProps
in JSX
TypeScript 2.9 及更早版本未在 JSX 组件内利用 React defaultProps
声明。用户通常需要在 render
内部将属性声明为可选属性并使用非空断言,或者在导出组件之前使用类型断言来修复组件的类型。
¥TypeScript 2.9 and earlier didn’t leverage React defaultProps
declarations inside JSX components.
Users would often have to declare properties optional and use non-null assertions inside of render
, or they’d use type-assertions to fix up the type of the component before exporting it.
TypeScript 3.0 在 JSX
命名空间中增加了对名为 LibraryManagedAttributes
的新类型别名的支持。此辅助类型定义了组件 Props
类型的转换,然后再用于检查针对该类型的 JSX 表达式;因此允许进行如下自定义:如何处理提供的 props 和推断的 props 之间的冲突,如何映射推断,如何处理可选性,以及如何组合来自不同位置的推断。
¥TypeScript 3.0 adds support for a new type alias in the JSX
namespace called LibraryManagedAttributes
.
This helper type defines a transformation on the component’s Props
type, before using to check a JSX expression targeting it; thus allowing customization like: how conflicts between provided props and inferred props are handled, how inferences are mapped, how optionality is handled, and how inferences from differing places should be combined.
简而言之,使用这种通用类型,我们可以为 React 针对 defaultProps
以及某种程度上的 propTypes
等特定行为建模。
¥In short using this general type, we can model React’s specific behavior for things like defaultProps
and, to some extent, propTypes
.
tsx
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" };}// Type-checks! No type assertions needed!let el = <Greet />;
警告
¥Caveats
defaultProps
上的显式类型
¥Explicit types on defaultProps
默认属性是从 defaultProps
属性类型推断出来的。如果添加了显式类型注释,例如 static defaultProps: Partial<Props>;
,编译器将无法识别哪些属性具有默认值(因为 defaultProps
的类型包含 Props
的所有属性)。
¥The default-ed properties are inferred from the defaultProps
property type. If an explicit type annotation is added, e.g. static defaultProps: Partial<Props>;
the compiler will not be able to identify which properties have defaults (since the type of defaultProps
include all properties of Props
).
改为使用 static defaultProps: Pick<Props, "name">;
作为显式类型注释,或者不要像上面的示例那样添加类型注释。
¥Use static defaultProps: Pick<Props, "name">;
as an explicit type annotation instead, or do not add a type annotation as done in the example above.
对于函数组件(以前称为 SFC),请使用 ES2015 默认初始化器:
¥For function components (formerly known as SFCs) use ES2015 default initializers:
tsx
function Greet({ name = "world" }: Props) {return <div>Hello {name.toUpperCase()}!</div>;}
@types/React
的变更
¥Changes to @types/React
仍然需要进行相应的更改,将 LibraryManagedAttributes
定义添加到 @types/React
中的 JSX
命名空间。请记住,存在一些限制。
¥Corresponding changes to add LibraryManagedAttributes
definition to the JSX
namespace in @types/React
are still needed.
Keep in mind that there are some limitations.
/// <reference lib="..." />
引用指令
¥/// <reference lib="..." />
reference directives
TypeScript 添加了一个新的三斜杠引用指令 (/// <reference lib="name" />
),允许文件显式包含现有的内置库文件。
¥TypeScript adds a new triple-slash-reference directive (/// <reference lib="name" />
), allowing a file to explicitly include an existing built-in lib file.
内置 lib 文件的引用方式与 tsconfig.json 中的 lib
编译器选项相同(例如,使用 lib="es2015"
而不是 lib="lib.es2015.d.ts"
等)。
¥Built-in lib files are referenced in the same fashion as the lib
compiler option in tsconfig.json (e.g. use lib="es2015"
and not lib="lib.es2015.d.ts"
, etc.).
对于依赖内置类型的声明文件作者,例如建议使用 DOM API 或内置 JS 运行时构造函数,如 Symbol
或 Iterable
,三斜杠引用 lib 指令。以前这些 .d.ts 文件必须添加此类类型的前向/重复声明。
¥For declaration file authors who rely on built-in types, e.g. DOM APIs or built-in JS run-time constructors like Symbol
or Iterable
, triple-slash-reference lib directives are recommended. Previously these .d.ts files had to add forward/duplicate declarations of such types.
示例
¥Example
在编译过程中对某个文件使用 /// <reference lib="es2017.string" />
相当于使用 --lib es2017.string
进行编译。
¥Using /// <reference lib="es2017.string" />
to one of the files in a compilation is equivalent to compiling with --lib es2017.string
.
ts
/// <reference lib="es2017.string" />"foo".padStart(4);