このページの実行環境 例はNode.js 20以降を想定しています。グローバルの
fetchはNode.js 18以降でフラグなしで利用でき、node:testはNode.js 20で安定版になりました。版によってAPIや出力が異なる場合があるため、node --versionも確認してください。Promiseは将来の結果を表す
通信やファイル操作は、結果がすぐには返らない非同期処理です。Promise<T>は、将来成功したときにTが得られることを表します。
少し後で値を返すTYPESCRIPT
function waitMessage(): Promise<string> {
return new Promise((resolve) => {
setTimeout(() => resolve("完了"), 100);
});
}
waitMessage().then((message) => console.log(message));実行結果OUTPUT
完了async/awaitで完了を待つ
awaitはPromiseの結果が決まるまで、その非同期関数の続きだけを待ちます。awaitを使う関数にはasyncを付け、戻り値はPromiseになります。
順番を確認TYPESCRIPT
const delay = (ms: number): Promise<void> =>
new Promise((resolve) => setTimeout(resolve, ms));
async function main(): Promise<void> {
console.log("開始");
await delay(100);
console.log("終了");
}
await main();実行結果OUTPUT
開始
終了トップレベルawaitの前提 この例の
await main();を関数の外に書くには、出力したJavaScriptをES Modulesとして実行する必要があります。package.jsonの"type": "module"など、必要な設定はモジュールとプロジェクト設定を参照してください。前節のwaitMessage().then(...)はトップレベルawaitを使わない点が異なります。外部データは実行時に検証する
response.json()で得る値は外部から来ます。自分で型を書くだけでは内容を保証できないため、unknownとして検証します。
投稿タイトルを取得TYPESCRIPT
type Post = { id: number; title: string };
function isPost(value: unknown): value is Post {
if (typeof value !== "object" || value === null) return false;
const item = value as Record<string, unknown>;
return typeof item.id === "number" && typeof item.title === "string";
}
async function fetchPost(url: string): Promise<Post> {
const response = await fetch(url);
if (!response.ok) throw new Error(`HTTP ${response.status}`);
const data: unknown = await response.json();
if (!isPost(data)) throw new Error("レスポンスの形式が不正です");
return data;
}実際の出力は接続先と時期で変わります。通信処理は成功例だけでなく、タイムアウト、HTTPエラー、不正なJSONも想定します。
catchした値を安全に扱う
JavaScriptではError以外もthrowできるため、catchした値はunknownとして絞り込みます。
失敗を表示TYPESCRIPT
function parseCount(text: string): number {
const value = Number(text);
if (!Number.isInteger(value) || value < 0) {
throw new Error("0以上の整数を指定してください");
}
return value;
}
try {
console.log(parseCount("三"));
} catch (error: unknown) {
const message = error instanceof Error ? error.message : "不明なエラー";
console.log(message);
}実行結果OUTPUT
0以上の整数を指定してください握りつぶさない 空のcatchで失敗を無視すると原因を調べられません。利用者向け表示と、調査に必要なログを分けて設計します。
Node.js標準機能でテストする
ここでは依存を増やさず、Node.jsのnode:testとnode:assert/strictを使います。先に@types/nodeを開発用依存へ追加します。
src/price.tsTYPESCRIPT
export function calculateTotal(price: number, count: number): number {
if (price < 0 || !Number.isInteger(count) || count < 0) {
throw new Error("価格と個数を確認してください");
}
return price * count;
}src/price.test.tsTYPESCRIPT
import test from "node:test";
import assert from "node:assert/strict";
import { calculateTotal } from "./price.js";
test("単価と個数から合計を計算する", () => {
assert.equal(calculateTotal(200, 3), 600);
});
test("負の個数を拒否する", () => {
assert.throws(() => calculateTotal(200, -1));
});ビルド後に実行COMMAND
npm run build
node --test dist/price.test.js結果の要点OUTPUT
tests 2
pass 2
fail 0成功する通常値だけでなく、0、負数、空の値など境界や失敗も確認します。詳細表示はNode.jsの版で異なります。
ミニ課題:安全なJSON変換
JSON文字列を受け取り、{ name: string; quantity: number }の形なら値を返し、それ以外ならエラーにする非同期関数を作ってください。正常なJSON、不正な構文、プロパティ不足、負の個数をテストします。
確認の順序
JSON.parseの例外を扱う- 結果を
unknownとして検証する - quantityが0以上の整数か確認する
- 成功と複数の失敗をテストする
