这是一种奇怪的行为!
事实上,只有sealExhibit
包含了undefined
值,但是它却让lion
也含有了undefined
值。
得益于Jack Bates提交的,这个问题已经被修复了,它改进了TypeScript 3.9中的类型推断流程。
上面的例子中已经不再产生错误。
如果你在旧版本的TypeScript中被Promise
的这个问题所困扰,我们建议你尝试一下3.9版本!
如果你一直关注TypeScript,那么你可能会注意到一个新的类型运算符awaited
。
这个类型运算符的作用是准确地表达JavaScript中Promise
的工作方式。
我们原计划在TypeScript 3.9中支持awaited
,但在现有的代码中测试过该特性后,我们发现还需要进行一些设计,以便让所有人能够顺利地使用它。
因此,我们从主分支中暂时移除了这个特性。
我们将继续试验这个特性,它不会被包含进本次发布。
TypeScript 3.9提供了多项速度优化。
TypeScript在material-ui
和styled-components
代码包中拥有非常慢的编辑速度和编译速度。在发现了这点后,TypeScript团队集中了精力解决性能问题。
TypeScript优化了大型联合类型、交叉类型、有条件类型和映射类型。
- https://github.com/microsoft/TypeScript/pull/36590
- https://github.com/microsoft/TypeScript/pull/36622
- https://github.com/microsoft/TypeScript/pull/36696
上面列出的每一个PR都能够减少5-10%的编译时间(对于某些代码库)。
对于material-ui
库而言,现在能够节约大约40%的编译时间!
我们还调整了在编辑器中的文件重命名功能。
从Visual Studio Code团队处得知,当重命名一个文件时,计算出需要更新的import
语句要花费5到10秒的时间。
TypeScript 3.9通过解决了这个问题。
尽管仍有优化的空间,我们希望当前的改变能够为每个人带来更流畅的体验。
设想一下,我们正在使用TypeScript编写一个代码库,它对外开放了一个公共函数doStuff
。
该函数的类型声明了它接受两个string
类型的参数,因此其它TypeScript的用户能够看到类型检查的结果,但该函数还进行了运行时的检查以便JavaScript用户能够看到一个有帮助的错误。
function doStuff(abc: string, xyz: string) {
assert(typeof abc === "string");
assert(typeof xyz === "string");
// do some stuff
}
如果有人错误地使用了该函数,那么TypeScript用户能够看到红色的波浪线和错误提示,JavaScript用户会看到断言错误。 然后,我们想编写一条单元测试来测试该行为。
expect(() => {
doStuff(123, 456);
}).toThrow();
不巧的是,如果你使用TypeScript来编译单元测试,TypeScript会提示一个错误!
doStuff(123, 456);
// ~~~
// 错误:类型'number'不能够赋值给类型'string'。
这就是TypeScript 3.9添加了// @ts-expect-error
注释的原因。
当一行代码带有// @ts-expect-error
注释时,TypeScript不会提示上例的错误;
但如果该行代码没有错误,TypeScript会提示没有必要使用// @ts-expect-error
。
示例,以下的代码是正确的:
// @ts-expect-error
console.log(47 * "octopus");
会产生错误:
未使用的 '@ts-expect-error' 指令。
非常感谢Josh Goldberg实现了这个功能。 更多信息请参考。
ts-ignore
还是 ts-expect-error
?
某些情况下,和// @ts-ignore
是相似的,都能够阻止产生错误消息。
两者的不同在于,如果下一行代码没有错误,那么// @ts-ignore
不会做任何事。
你可能会想要抛弃// @ts-ignore
注释转而去使用// @ts-expect-error
,并且想要知道哪一个更适用于以后的代码。
实际上,这完全取决于你和你的团队,下面列举了一些具体情况。
如果满足以下条件,那么选择ts-expect-error
:
- 你在编写单元测试,并且想让类型系统提示错误
- 你知道此处有问题,并且很快会回来改正它,只是暂时地忽略该错误
- 你的团队成员都很积极,大家想要在代码回归正常后及时地删除忽略类型检查注释
如果满足以下条件,那么选择ts-ignore
:
- 项目规模较大,产生了一些错误但是找不到相应代码的负责人
- 正处于TypeScript版本升级的过程中,某些错误只在特定版本的TypeScript中存在,但是在其它版本中并不存在
- 你没有足够的时间考虑究竟应该使用
// @ts-ignore
还是// @ts-expect-error
在TypeScript 3.7中,我们引入了未进行函数调用的检查,当你忘记去调用某个函数时会产生错误。
// ...
}
// Oops!
if (hasImportantPermissions) {
// ~~~~~~~~~~~~~~~~~~~~~~~
// 这个条件永远返回true,因为函数已经被定义。
// 你是否想要调用该函数?
deleteAllTheImportantFiles();
}
然而,这个错误只会在if
条件语句中才会提示。
多亏了提交的PR,现在这个特性也支持在三元表达式中使用,例如cond ? trueExpr : falseExpr
。
declare function listFilesOfDirectory(dirPath: string): string[];
declare function isDirectory(): boolean;
function getAllFiles(startFileName: string) {
const result: string[] = [];
traverse(startFileName);
return result;
function traverse(currentPath: string) {
return isDirectory
? // ~~~~~~~~~~~
// 该条件永远返回true
// 因为函数已经被定义。
// 你是否想要调用该函数?
listFilesOfDirectory(currentPath).forEach(traverse)
: result.push(currentPath);
}
}
TypeScript编译器不但支持在大部分编辑器中编写TypeScript代码,还支持着在Visual Studio系列的编辑器中编写JavaScript代码。 针对不同的编辑器,在使用TypeScript/JavaScript的新功能时可能会有所区别,但是
- Visual Studio Code支持选择不同的TypeScript版本。或者,安装插件来使用最新的版本。
- Visual Studio 2017/2019提供了SDK安装包,以及MSBuild安装包。
- Sublime Text 3支持
在使用了CommonJS模块的JavaScript文件中,我们对自动导入功能进行了一个非常棒的改进。
在旧的版本中,TypeScript总是假设你想要使用ECMAScript模块风格的导入语句,并且无视你的文件类型。
import * as fs from "fs";
然而,在编写JavaScript文件时,并不总是想要使用ECMAScript模块风格。
非常多的用户仍然在使用CommonJS模块,例如require(...)
。
更新信息请参考PR.
Code Actions 保留换行符
TypeScript的重构工具和快速修复工具对换行符的处理不是非常好。 一个基本的示例如下。
const maxValue = 100;
/*start*/
for (let i = 0; i <= maxValue; i++) {
// First get the squared value.
// Now print the squared value.
console.log(square);
}
/*end*/
如果我们选中从/*start*/
到/*end*/
,然后进行“提取到函数”操作,我们会得到如下的代码。
const maxValue = 100;
printSquares();
function printSquares() {
for (let i = 0; i <= maxValue; i++) {
// First get the squared value.
let square = i ** 2;
// Now print the squared value.
console.log(square);
}
}
这不是我们想要的 - 在for
循环中,每条语句之间都有一个空行,但是重构后它们被移除了!
TypeScript 3.9调整后,它会保留我们编写的代码。
const maxValue = 100;
printSquares();
function printSquares() {
for (let i = 0; i <= maxValue; i++) {
// First get the squared value.
let square = i ** 2;
// Now print the squared value.
console.log(square);
}
}
更多信息请参考PR
有时候,我们可能忘记在函数的最后添加返回值语句,尤其是在将简单箭头函数转换成还有花括号的箭头函数时。
// before
let f1 = () => 42;
// oops - not the same!
let f2 = () => {
42;
};
感谢开源社区的的PR,TypeScript提供了快速修复功能来添加return
语句,删除花括号,或者为箭头函数体添加小括号用以区分对象字面量。
支持”Solution Style”的tsconfig.json
文件
编译器需要知道一个文件被哪个配置文件所管理,因此才能够应用适当的配置选项并且计算出当前“工程”包含了哪些文件。
在默认情况下,编辑器使用TypeScript语言服务来向上遍历父级目录以查找tsconfig.json
文件。
有一种特殊情况是tsconfig.json
文件仅用于引用其它tsconfig.json
文件。
这个文件除了用来管理其它项目的配置文件之外什么也没做,在某些环境中它被叫作“solution”。
这里,任何一个tsconfig.*.json
文件都不会被TypeScript语言服务所选用,但是我们希望语言服务能够分析出当前的.ts
文件被上述tsconfig.json
中引用的哪个配置文件所管理。