JavaScriptにおいて Promise や async/await は日常的に使用しますが、TypeScriptでは「将来どのような値が返ってくるか」を明示する必要があります。
また、既存の型を再利用して新しい型を作る「ユーティリティ型」を学ぶことで、コードの重複を劇的に減らすことができます。
JavaScriptでは、非同期関数の戻り値は常に Promise オブジェクトです。TypeScriptでは、このPromiseが解決(Resolve)されたときに持つ値の型をジェネリクスを使って Promise<T> の形式で表現します。
Promise<string>
Promise<number>Promise<void>async キーワードがついた関数は、自動的に戻り値が Promise でラップされます。
type User = {
id: number;
name: string;
email: string;
};
// 擬似的なAPIコール関数
// 戻り値の型として Promise<User> を指定します
const fetchUser = async (userId: number): Promise<User> => {
// 実際はfetchなどを行いますが、ここでは擬似的に遅延させて値を返します
return new Promise((resolve) => {
setTimeout(() => {
resolve({
id: userId,
name: "Yamada Taro",
email: "taro@example.com",
});
}, 500);
});
};
const main = async () => {
console.log("Fetching data...");
// awaitを使うことで、user変数の型は自動的に User 型(Promiseが解けた状態)になります
const user = await fetchUser(1);
console.log(`ID: ${user.id}`);
console.log(`Name: ${user.name}`);
};
main();npx tsc async-fetch.ts && node async-fetch.jsFetching data... ID: 1 Name: Yamada Taro
Promiseが拒否(Reject)される場合のエラー型は、現状のTypeScriptではデフォルトで any または unknown として扱われます(try-catch ブロックの error オブジェクトなど)。
TypeScriptには、既存の型定義を変換して新しい型を生成するための便利な型が標準で用意されています。これらを使うと、「一部のプロパティだけ変更したい」「全てオプショナルにしたい」といった場合に、いちいち新しい型を定義し直す必要がなくなります。
ここでは、特によく使われる4つのユーティリティ型を紹介します。
以下の Product 型を例に使用します。
interface Product {
id: number;
name: string;
price: number;
description: string;
}Partial<T> は、型 T のすべてのプロパティを「必須」から「任意(Optional / ?付き)」に変更します。データの更新処理(パッチ)などで、一部のフィールドだけ送信したい場合に便利です。
interface Product {
id: number;
name: string;
price: number;
description: string;
}
// プロパティの一部だけを更新する関数
// updateDataは { name?: string; price?: number; ... } のようになります
function updateProduct(id: number, updateData: Partial<Product>) {
console.log(`Updating product ${id} with:`, updateData);
}
// nameとpriceだけ更新(descriptionやidがなくてもエラーにならない)
updateProduct(100, {
name: "New Product Name",
price: 5000
});npx tsc utility-partial.ts && node utility-partial.jsUpdating product 100 with: { name: 'New Product Name', price: 5000 }Readonly<T> は、型 T のすべてのプロパティを書き換え不可(readonly)にします。関数内でオブジェクトを変更されたくない場合や、ReactのState管理などで役立ちます。
interface Product {
id: number;
name: string;
price: number;
}
const originalProduct: Product = { id: 1, name: "Pen", price: 100 };
// 変更不可のオブジェクトとして扱う
const frozenProduct: Readonly<Product> = originalProduct;
// 読み取りはOK
console.log(frozenProduct.name);
// コンパイルエラー: 値の代入はできません
// frozenProduct.price = 200; npx tsc utility-readonly.ts && node utility-readonly.jsPen
Pick<T, K> は、型 T から K で指定したプロパティのみを抽出して新しい型を作ります。
「ユーザー情報全体から、表示用の名前と画像URLだけ欲しい」といった場合に使います。
interface Product {
id: number;
name: string;
price: number;
description: string;
stock: number;
}
// 商品一覧表示用に、IDと名前と価格だけが必要な型を作る
type ProductPreview = Pick<Product, "id" | "name" | "price">;
const item: ProductPreview = {
id: 1,
name: "Laptop",
price: 120000,
// description: "..." // エラー: ProductPreviewにはdescriptionは存在しません
};
console.log(item);npx tsc utility-pick.ts && node utility-pick.js{ id: 1, name: 'Laptop', price: 120000 }Omit<T, K> は Pick の逆で、指定したプロパティを除外します。
「データベースのモデルから、機密情報や内部管理用のIDを除外してクライアントに返したい」といった場合に有用です。
interface Product {
id: number;
name: string;
price: number;
secretCode: string; // 外部に出したくない情報
internalId: string; // 外部に出したくない情報
}
// 外部公開用の型(secretCodeとinternalIdを除外)
type PublicProduct = Omit<Product, "secretCode" | "internalId">;
const publicItem: PublicProduct = {
id: 1,
name: "Mouse",
price: 3000
};
console.log(publicItem);npx tsc utility-omit.ts && node utility-omit.js{ id: 1, name: 'Mouse', price: 3000 }ここでは詳細な文法までは踏み込みませんが、ライブラリの型定義などを読む際に遭遇する高度な概念を紹介します。これらは上記のユーティリティ型の内部実装にも使われています。
既存の型のプロパティをループ処理して、新しい型を作る機能です。配列の .map() の型バージョンと考えると分かりやすいでしょう。
type Item = { a: string; b: number };
// 既存のItemのキー(P)をすべて boolean 型に変換する
type BooleanItem = {
[P in keyof Item]: boolean;
};
// 結果: { a: boolean; b: boolean; } と等価型の三項演算子のようなものです。「もし型Tが型Uを継承しているならX型、そうでなければY型」という条件分岐を定義できます。
// Tがstringなら number[] を、それ以外なら T[] を返す型 type StringArrayOrGeneric<T> = T extends string ? number[] : T[]; type A = StringArrayOrGeneric<string>; // number[] になる type B = StringArrayOrGeneric<boolean>; // boolean[] になる
async 関数の戻り値は Promise<T> で定義する。
Partial<T>: 全プロパティを任意にする。Readonly<T>: 全プロパティを読み取り専用にする。Pick<T, K>: 必要なプロパティだけ抽出する。Omit<T, K>: 不要なプロパティを除外する。Mapped Types や Conditional Types を使うことで、動的で柔軟な型定義が可能になる。JavaScriptの柔軟性を保ちつつ、堅牢さを加えるためにこれらの機能は非常に重要です。特にユーティリティ型は、冗長なコードを減らす即戦力の機能ですので、ぜひ活用してください。
Post というインターフェースを定義してください(id: number, title: string, body: string)。fetchPost という async 関数を作成してください。この関数は引数に id (number) を受け取り、戻り値として Promise<Post> を返します。setTimeoutなどは不要です)。npx tsc practice8_1.ts && node practice8_1.jsアプリケーションの設定を表す AppConfig インターフェースがあります。
以下の要件を満たす新しい型と変数を定義してください。
AppConfig から debugMode を除外した型 ProductionConfig を定義してください (Omitを使用)。AppConfig のすべてのプロパティを**任意(Optional)**にした型 OptionalConfig を定義してください (Partialを使用)。ProductionConfig 型を持つ変数 prodConfig を定義し、適切な値を代入してください。interface AppConfig {
apiUrl: string;
retryCount: number;
timeout: number;
debugMode: boolean;
}npx tsc practice8_2.ts && node practice8_2.js