支持混合类
🌐 Support for Mix-in classes
TypeScript 2.2 添加了对 ECMAScript 2015 混入类模式的支持(更多详情请参见 MDN 混入描述 和 使用 JavaScript 类的“真实”混入),以及在交叉类型中将混入构造签名与常规构造签名结合的规则。
🌐 TypeScript 2.2 adds support for the ECMAScript 2015 mixin class pattern (see MDN Mixin description and “Real” Mixins with JavaScript Classes for more details) as well as rules for combining mixin construct signatures with regular construct signatures in intersection types.
首先介绍一些术语
🌐 First some terminology
混入构造函数类型是指具有单一构造签名,且该签名带有类型为 any[] 的单个剩余参数,并返回类似对象类型的类型。例如,给定一个类似对象的类型 X,new (...args: any[]) => X 是一个混入构造函数类型,其实例类型为 X。
🌐 A mixin constructor type refers to a type that has a single construct signature with a single rest argument of type any[] and an object-like return type. For example, given an object-like type X, new (...args: any[]) => X is a mixin constructor type with an instance type X.
Mixin 类是一种类声明或表达式,它 extends 一个类型参数类型的表达式。以下规则适用于 mixin 类声明:
🌐 A mixin class is a class declaration or expression that extends an expression of a type parameter type. The following rules apply to mixin class declarations:
extends表达式的类型参数类型必须被约束为混入构造函数类型。- 混入类的构造函数(如果有的话)必须有一个类型为
any[]的剩余参数,并且必须使用展开运算符将这些参数作为super(...args)调用的参数传递。
给定一个参数化类型 T 的表达式 Base,并带有约束 X,混入类 class C extends Base {...} 的处理方式就好像 Base 的类型是 X,最终得到的类型是交集 typeof C & T。
换句话说,混入类被表示为混入类构造函数类型与参数化基类构造函数类型之间的交集。
🌐 Given an expression Base of a parametric type T with a constraint X, a mixin class class C extends Base {...} is processed as if Base had type X and the resulting type is the intersection typeof C & T.
In other words, a mixin class is represented as an intersection between the mixin class constructor type and the parametric base class constructor type.
当获取包含混入构造类型的交叉类型的构造签名时,混入构造签名会被丢弃,其实例类型会混入交叉类型中其他构造签名的返回类型中。例如,交叉类型 { new(...args: any[]) => A } & { new(s: string) => B } 有一个单一的构造签名 new(s: string) => A & B。
🌐 When obtaining the construct signatures of an intersection type that contains mixin constructor types, the mixin construct signatures are discarded and their instance types are mixed into the return types of the other construct signatures in the intersection type.
For example, the intersection type { new(...args: any[]) => A } & { new(s: string) => B } has a single construct signature new(s: string) => A & B.
将以上所有规则整合到一个示例中
🌐 Putting all of the above rules together in an example
tsclass Point {constructor(public x: number, public y: number) {}}class Person {constructor(public name: string) {}}type Constructor<T> = new (...args: any[]) => T;function Tagged<T extends Constructor<{}>>(Base: T) {return class extends Base {_tag: string;constructor(...args: any[]) {super(...args);this._tag = "";}};}const TaggedPoint = Tagged(Point);let point = new TaggedPoint(10, 20);point._tag = "hello";class Customer extends Tagged(Person) {accountBalance: number;}let customer = new Customer("Joe");customer._tag = "test";customer.accountBalance = 0;
Mixin 类可以通过在类型参数的约束中指定构造签名返回类型来限制它们可以混入的类的类型。例如,以下 WithLocation 函数实现了一个子类工厂,它向任何满足 Point 接口的类添加 getLocation 方法(即具有 x 和 y 属性且类型为 number)。
🌐 Mixin classes can constrain the types of classes they can mix into by specifying a construct signature return type in the constraint for the type parameter.
For example, the following WithLocation function implements a subclass factory that adds a getLocation method to any class that satisfies the Point interface (i.e. that has x and y properties of type number).
tsinterface Point {x: number;y: number;}const WithLocation = <T extends Constructor<Point>>(Base: T) =>class extends Base {getLocation(): [number, number] {return [this.x, this.y];}};
object 型
🌐 object type
TypeScript 没有表示非原始类型的类型,即任何不是 number、string、boolean、symbol、null 或 undefined 的东西。引入了新的 object 类型。
🌐 TypeScript did not have a type that represents the non-primitive type, i.e. any thing that is not number, string, boolean, symbol, null, or undefined. Enter the new object type.
使用 object 类型,可以更好地表示像 Object.create 这样的 API。例如:
🌐 With object type, APIs like Object.create can be better represented. For example:
tsdeclare function create(o: object | null): void;create({ prop: 0 }); // OKcreate(null); // OKcreate(42); // Errorcreate("string"); // Errorcreate(false); // Errorcreate(undefined); // Error
支持 new.target
🌐 Support for new.target
new.target 元属性是 ES2015 中引入的新语法。当通过 new 创建构造函数的实例时,new.target 的值被设置为最初用于分配该实例的构造函数的引用。如果调用的是函数而不是通过 new 构造,那么 new.target 被设置为 undefined。
🌐 The new.target meta-property is new syntax introduced in ES2015.
When an instance of a constructor is created via new, the value of new.target is set to be a reference to the constructor function initially used to allocate the instance.
If a function is called rather than constructed via new, new.target is set to undefined.
new.target 在需要在类构造函数中设置 Object.setPrototypeOf 或 __proto__ 时非常有用。一个这样的使用场景是在 NodeJS v4 及更高版本中继承 Error。
示例
🌐 Example
tsclass CustomError extends Error {constructor(message?: string) {super(message); // 'Error' breaks prototype chain hereObject.setPrototypeOf(this, new.target.prototype); // restore prototype chain}}
生成的 JS 代码如下
🌐 This results in the generated JS
jsvar CustomError = (function(_super) {__extends(CustomError, _super);function CustomError() {var _newTarget = this.constructor;var _this = _super.apply(this, arguments); // 'Error' breaks prototype chain here_this.__proto__ = _newTarget.prototype; // restore prototype chainreturn _this;}return CustomError;})(Error);
new.target 在编写可构造函数时也非常有用,例如:
tsfunction f() {if (new.target) {/* called via 'new' */}}
翻译为:
🌐 Which translates to:
jsfunction f() {var _newTarget = this && this instanceof f ? this.constructor : void 0;if (_newTarget) {/* called via 'new' */}}
更好地检查表达式操作数中的 null/undefined
🌐 Better checking for null/undefined in operands of expressions
TypeScript 2.2 改进了对表达式中可为空操作数的检查。具体来说,现在这些情况会被标记为错误:
🌐 TypeScript 2.2 improves checking of nullable operands in expressions. Specifically, these are now flagged as errors:
- 如果
+运算符的任一操作数可为空,并且两个操作数都不是any或string类型。 - 如果
-、*、**、/、%、<<、>>、>>>、&、|或^运算符的任一操作数可为空。 - 如果
<、>、<=、>=或in运算符的任一操作数可为空。 - 如果
instanceof运算符的右操作数可以为空。 - 如果
+、-、~、++或--一元运算符的操作数可为空。
如果操作数的类型是 null 或 undefined,或者是包含 null 或 undefined 的联合类型,则该操作数被视为可为空。请注意,联合类型的情况仅在 strictNullChecks 模式下出现,因为在经典类型检查模式下,null 和 undefined 会从联合类型中消失。
🌐 An operand is considered nullable if the type of the operand is null or undefined or a union type that includes null or undefined.
Note that the union type case only occurs in strictNullChecks mode because null and undefined disappear from unions in classic type checking mode.
带有字符串索引签名的类型的点属性
🌐 Dotted property for types with string index signatures
具有字符串索引签名的类型可以使用 [] 语法进行索引,但不允许使用 .。从 TypeScript 2.2 开始,应该允许使用任意一种语法。
🌐 Types with a string index signature can be indexed using the [] notation, but were not allowed to use the ..
Starting with TypeScript 2.2 using either should be allowed.
tsinterface StringMap<T> {[x: string]: T;}const map: StringMap<number>;map["prop1"] = 1;map.prop2 = 2;
这仅适用于具有 显式 字符串索引签名的类型。使用 . 记法访问类型上未知的属性仍然会报错。
🌐 This only applies to types with an explicit string index signature.
It is still an error to access unknown properties on a type using . notation.
支持 JSX 元素子元素上的展开运算符
🌐 Support for spread operator on JSX element children
TypeScript 2.2 增加了对在 JSX 元素子项上使用扩展运算符的支持。请参阅 facebook/jsx#57 获取更多详情。
🌐 TypeScript 2.2 adds support for using spread on JSX element children. Please see facebook/jsx#57 for more details.
示例
🌐 Example
tsfunction Todo(prop: { key: number; todo: string }) {return <div>{prop.key.toString() + prop.todo}</div>;}function TodoList({ todos }: TodoListProps) {return (<div>{...todos.map(todo => <Todo key={todo.id} todo={todo.todo} />)}</div>);}let x: TodoListProps;<TodoList {...x} />;
新的 jsx: react-native
🌐 New jsx: react-native
React-native 构建流程期望所有文件都使用 .js 扩展名,即使文件包含 JSX 语法。新的 jsx 值 react-native 将在输出文件中保留 JSX 语法,但会使用 .js 扩展名。
🌐 React-native build pipeline expects all files to have a .js extension even if the file contains JSX syntax.
The new jsx value react-native will preserve the JSX syntax in the output file, but give it a .js extension.