TypeScriptでPromise.all・Promise.raceの型安全な書き方をやさしく解説
生徒
「TypeScriptで複数の処理を同時に実行できると聞いたんですが、本当にそんなことができるんですか?」
先生
「できますよ。Promise.allやPromise.raceという仕組みを使うと、同時に進む処理をまとめて扱えます。」
生徒
「でも型安全って何ですか?型があると何がうれしいんですか?」
先生
「型安全とは、間違った使い方をコンピュータが事前に教えてくれる状態のことです。TypeScriptならPromise.allやPromise.raceも安心して使えます。」
1. Promiseとは何かを超かんたんに説明
TypeScriptやJavaScriptでは、時間がかかる処理をそのまま待つと、画面や操作が止まってしまいます。そこで使われるのがPromiseです。Promiseは「あとで結果が返ってくる約束」のようなものです。
たとえば、料理を注文してから出てくるまでを想像してください。注文した瞬間に料理はありませんが、しばらくすると完成します。この「あとで完成する料理」がPromiseのイメージです。
TypeScriptでは、このPromiseに「どんな結果が返ってくるか」という型をつけられるため、より安全にプログラムを書けます。
2. Promise.allとは?同時に全部そろうのを待つ仕組み
Promise.allは、複数のPromiseをまとめて扱うための機能です。すべてのPromiseが終わったら、まとめて結果を受け取れます。
これは「お弁当を注文して、全部そろってから食べ始める」ようなイメージです。一つでもまだ来ていなければ、待ち続けます。
const p1: Promise<number> = Promise.resolve(1);
const p2: Promise<string> = Promise.resolve("apple");
Promise.all([p1, p2]).then(result => {
console.log(result);
});
この場合、resultの中身は「数値と文字列が入った配列」になります。TypeScriptでは自動的に型を推測してくれるため、間違った使い方をするとエラーで教えてくれます。
[1, "apple"]
3. Promise.allを型安全に使うポイント
型安全に使うために大切なのは、「Promiseの中身の型をはっきりさせる」ことです。Promise.allは、配列の順番通りに結果が返るため、順番も重要になります。
TypeScriptでは、タプルという仕組みを使うと、配列の中身を固定できます。これにより、どこに何の型が入っているかが明確になります。
const promises = [
Promise.resolve(10),
Promise.resolve(true)
] as const;
Promise.all(promises).then(([count, flag]) => {
console.log(count, flag);
});
このように書くことで、countは数値、flagは真偽値と決まり、間違った操作を防げます。
4. Promise.raceとは?一番早いものを使う仕組み
Promise.raceは、複数のPromiseの中で、最初に終わったものだけを使う仕組みです。
これは「かけっこで一番にゴールした人だけを見る」ようなイメージです。ほかの人がまだ走っていても、最初の結果だけを採用します。
const fast = new Promise<string>(resolve => {
setTimeout(() => resolve("fast"), 100);
});
const slow = new Promise<string>(resolve => {
setTimeout(() => resolve("slow"), 1000);
});
Promise.race([fast, slow]).then(result => {
console.log(result);
});
fast
5. Promise.raceを型安全に使う考え方
Promise.raceでは、どのPromiseが勝つかわからないため、戻り値の型は「すべてのPromiseの型をまとめたもの」になります。
もし数値と文字列が混ざっていれば、「数値か文字列のどちらか」という型になります。これを理解しておくと、後で混乱しません。
const pA = Promise.resolve(100);
const pB = Promise.resolve("hello");
Promise.race([pA, pB]).then(value => {
console.log(value);
});
このvalueは数値か文字列の可能性があるため、TypeScriptは慎重に扱うよう促してくれます。これが型安全の考え方です。
6. ES6とTypeScriptの連携としてのPromise
Promise自体はES6という新しめのJavaScriptの機能です。TypeScriptは、このES6の仕組みをそのまま使いながら、型を追加できる点が特徴です。
つまり、Promise.allやPromise.raceはJavaScriptの機能ですが、TypeScriptを使うことで「間違えにくいPromise処理」に変わります。
初心者のうちは難しく感じますが、「同時に進む作業を安全にまとめる道具」と考えると理解しやすくなります。