トップレベルawait
次に紹介するテーマは、「トップレベルawait」と呼ばれるものです。
awaitの使い方の確認
ここで紹介するテーマは、そのテーマ名からもわかるように、awaitキーワードの使い方に関するものです。このawaitは、非同期処理でよく登場するキーワードです。
非同期処理を含む関数はasync関数とも呼ばれ、その関数宣言にはasyncキーワードをつけるようになっています。そして、その関数からの戻り値は、Promiseオブジェクトでラップされるようになっています。例えば、リスト8のようなコードです。
async function doProcess(name: string): Promise<string> { // (1) : return str; // (2) } const promise = doProcess("しんちゃん"); // (3) promise.then( // (4) (result) => { // (5) console.log(result); // (6) } );
リスト8の(1)にasync関数doProcess()が定義されています。この関数は、引数として文字列nameを受け取り、それを非同期で加工処理を行いながら何かの文字列(str)を(2)のようにリターンする関数です。その場合、通常の関数なら、戻り値の型はstringとなります。一方、async関数の場合は、この本来の戻り値がラップされたPromiseオブジェクトがリターンされます。そのため、(1)のように、戻り値のデータ型はPromise<string>となります。
そして、この関数を実行した際のコードも、(3)のように戻り値は文字列ではなく、Promiseオブジェクトです。このPromiseオブジェクトから本来の戻り値を取得する場合は、(4)のようにthen()メソッドを利用して、その引数に、本来の戻り値を取得し、何かの処理を行う関数を渡す必要があります。リスト8では、(5)のアロー関数が該当し、その引数resultが本来の戻り値、すなわち、(2)のstrに該当します。(6)では、その戻り値をコンソール出力しています。
このように、単に関数の戻り値の文字列をコンソール出力する処理でさえも、非同期関数(async関数)の場合は、回りくどいコードを書く必要があります。このPromiseオブジェクトの処理を簡略化し、非同期処理の終了を待って本来の戻り値を取得するためのキーワードがawaitです。awaitを利用することで、リスト8の(3)〜(6)はリスト9のように書き換えることができます。
const result = await doProcess("しんちゃん"); console.log(result);
awaitの制約とその解消
このように便利なawaitですが、以前はひとつ制約がありました。それは、awaitを利用できるのは、async関数内のみである、というものです。よって、リスト9のコードは、実行ポイントとなるtsファイルの直下(=関数に括られていないトップレベル)に記述することはできません。
これが、ES2022では、実行ポイントであるjsファイルの直下に記述することが可能となり、これを「トップレベルawait」といいます。実は、このトップレベルawaitは、TypeScriptでは、ECMAScriptよりははるかに先行しており、2020年リリースのバージョン3.8で導入されています。
ただし、このトップレベルawaitを利用する場合は、コンパイルオプションとして、targetオプションをes2017以上に、moduleオプションをesnextかsystemにする必要がある点には注意してください。