keyof和映射类型支持用number和symbol命名的属性
TypeScript 2.9增加了在索引类型和映射类型上支持用number和symbol命名属性。 在之前,keyof操作符和映射类型只支持string命名的属性。
改动包括:
- 对某些类型T,索引类型keyof T是string | number | symbol的子类型。
- 映射类型{ [P in K]: XXX },其中K允许是可以赋值给string | number | symbol的任何值。
- 针对泛型T的对象的for...in语句,迭代变量推断类型之前为keyof T,现在是Extract<keyof T, string>。(换句话说,是keyof T的子集,它仅包含类字符串的值。)
对于对象类型X,keyof X将按以下方式解析:
- 如果X带有字符串索引签名,则keyof X为string,number和表示symbol-like属性的字面量类型的联合,否则
- 如果X带有数字索引签名,则keyof X为number和表示string-like和symbol-like属性的字面量类型的联合,否则
- keyof X为表示string-like,number-like和symbol-like属性的字面量类型的联合。
在何处:
- 对象类型的string-like属性,是那些使用标识符,字符串字面量或计算后值为字符串字面量类型的属性名所声明的。
- 对象类型的number-like属性是那些使用数字字面量或计算后值为数字字面量类型的属性名所声明的。
- 对象类型的symbol-like属性是那些使用计算后值为symbol字面量类型的属性名所声明的。
对于映射类型{ [P in K]: XXX },K的每个字符串字面量类型都会引入一个名字为字符串的属性,K的每个数字字面量类型都会引入一个名字为数字的属性,K的每个symbol字面量类型都会引入一个名字为symbol的属性。 并且,如果K包含string类型,那个同时也会引入字符串索引类型,如果K包含number类型,那个同时也会引入数字索引类型。
例子
ts
现在通过在键值类型里包含number类型,keyof就能反映出数字索引签名的存在,因此像Partial<T>和Readonly<T>的映射类型能够正确地处理带数字索引签名的对象类型:
ts
此外,由于keyof支持用number和symbol命名的键值,现在可以对对象的数字字面量(如数字枚举类型)和唯一的symbol属性的访问进行抽象。
ts
这是一个破坏性改动;之前,keyof操作符和映射类型只支持string命名的属性。 那些把总是把keyof T的类型当做string的代码现在会报错。
例子
ts
推荐
- 
如果函数只能处理字符串命名属性的键,在声明里使用 Extract<keyof T, string>:tsfunction useKey<T, K extends Extract<keyof T, string>>(o: T, k: K) {var name: string = k; // OK}
- 
如果函数能处理任何属性的键,那么可以在下游进行改动: tsfunction useKey<T, K extends keyof T>(o: T, k: K) {var name: string | number | symbol = k;}
- 
否则,使用 --keyofStringsOnly编译器选项来禁用新的行为。
JSX元素里的泛型参数
JSX元素现在允许传入类型参数到泛型组件里。
例子
ts
泛型标记模版里的泛型参数
标记模版是ECMAScript 2015引入的一种调用形式。 类似调用表达式,可以在标记模版里使用泛型函数,TypeScript会推断使用的类型参数。
TypeScript 2.9允许传入泛型参数到标记模版字符串。
例子
ts
import类型
模块可以导入在其它模块里声明的类型。但是非模块的全局脚本不能访问模块里声明的类型。这里,import类型登场了。
在类型注释的位置使用import("mod"),就可以访问一个模块和它导出的声明,而不必导入它。
例子
在一个模块文件里,有一个Pet类的声明:
ts
它可以被用在非模块文件global-script.ts:
ts
它也可以被放在.js文件的JSDoc注释里,来引用模块里的类型:
js
放开声明生成时可见性规则
随着import类型的到来,许多在声明文件生成阶段报的可见性错误可以被编译器正确地处理,而不需要改变输入。
例如:
ts
TypeScript 2.9不会报错,生成文件如下:
ts
支持import.meta
TypeScript 2.9引入对import.meta的支持,它是当前TC39建议里的一个元属性。
import.meta类型是全局的ImportMeta类型,它在lib.es5.d.ts里定义。 这个接口地使用十分有限。 添加众所周知的Node和浏览器属性需要进行接口合并,还有可能需要根据上下文来增加全局空间。
例子
假设__dirname永远存在于import.meta,那么可以通过重新开放ImportMeta接口来进行声明:
ts
用法如下:
ts
import.meta仅在输出目标为ESNext模块和ECMAScript时才生效。
新的--resolveJsonModule
在Node.js应用里经常需要使用.json。TypeScript 2.9的--resolveJsonModule允许从.json文件里导入,获取类型。
例子
ts
ts
ts
默认--pretty输出
从TypeScript 2.9开始,如果应用支持彩色文字,那么错误输出时会默认应用--pretty。 TypeScript会检查输出流是否设置了isTty属性。
使用--pretty false命令行选项或tsconfig.json里设置"pretty": false来禁用--pretty输出。
新的--declarationMap
随着--declaration一起启用--declarationMap,编译器在生成.d.ts的同时还会生成.d.ts.map。 语言服务现在也能够理解这些map文件,将声明文件映射到源码。
换句话说,在启用了--declarationMap后生成的.d.ts文件里点击go-to-definition,将会导航到源文件里的位置(.ts),而不是导航到.d.ts文件里。