async functionの中でしか使えなかったawaitがモジュールのTop Levelで使えるようになった。モジュールの中で以下のような書き方ができる。
```ts
async function lazyInit() {
// 中略
}
await lazyInit();
// 中略
export {};
```
ただしいくつか制約がある。
- [[Top-Level await]]を使うコードで `import`または`export`の記述が必要
- [[TypeScript]]がそれをもってファイルをmoduleであると判断するため
- [[target (tsconfig)|target]]が`es2017`以上でなければいけない
- [[module (tsconfig)|module]]が`esnext`または`system`でなければいけない
## 具体例
指定ミリ秒スリープさせる`asyncSleep`を呼ぶコードについて、[[Top-Level await]]の有無で`main.ts`がどのように変わるか比較してみる。
```ts
console.log("Load module.ts");
export const asyncSleep = (ms: number) =>
new Promise((resolve) => {
console.log("Begin sleep");
setTimeout(() => {
console.log("End sleep");
resolve();
}, ms);
});
```
### [[Top-Level await]]なし
`tsconfig.json`
```json
{
"compilerOptions": {
"target": "es2020",
"module": "CommonJS",
// 中略
}
}
```
`main.ts`
```ts
import { asyncSleep } from "./module.js";
console.log("Call asyncSleep begin");
await asyncSleep(3000);
console.log("Call asyncSleep end");
```
実行結果は以下のとおり。
```bash
Load module.ts
Call asyncSleep begin
Begin sleep
Call asyncSleep end
# 3秒待つ
End sleep
Finish
```
### [[Top-Level await]]あり
`tsconfig.json`
```json
{
"compilerOptions": {
"target": "es2020",
"module": "esnext",
// 中略
}
}
```
[[Node.jsがファイルをES modulesと認識する条件]]を満たすため、`package.json`と`main.ts`のimportを若干変更している。
`package.json`
```json
{
// 中略
"type": "module"
}
```
`main.ts`
```ts
// .js拡張子を追加
import { asyncSleep } from "./module.js";
console.log("Call asyncSleep begin");
await asyncSleep(3000);
console.log("Call asyncSleep end");
```
実行結果は以下のとおり。
```bash
Load module.ts
Call asyncSleep begin
Begin sleep
# 3秒待つ
End sleep
Call asyncSleep end
```