TypeScriptでフォーム・APIレスポンスなど共通型を汎用化する方法
生徒
「先生、TypeScriptでフォームやAPIレスポンスの型を毎回同じように書くのが面倒なんですが、もっと楽にできますか?」
先生
「とても良い質問ですね。TypeScriptでは“ジェネリクス(Generics)”を使えば、共通の型を汎用的に使い回すことができますよ。」
生徒
「ジェネリクスって何ですか?なんだか難しそうな名前ですね…。」
先生
「大丈夫ですよ。ジェネリクスは“型を後から指定できる仕組み”のことです。フォームデータやAPIレスポンスの型を共通化するのにとても便利なんです。」
生徒
「なるほど!じゃあ、どうやって使うのか教えてください!」
先生
「それでは、具体的な使い方を見ていきましょう!」
1. ジェネリクスで型を使い回すとは?
TypeScriptのジェネリクス(Generics)とは、「どんな型でも受け取れるけれど、使うときに具体的な型を指定できる」という仕組みです。
英語の「Generic(一般的な)」という言葉の通り、共通化された型を作るのに使います。
たとえば、ユーザー登録フォーム・商品登録フォームなど、似たようなデータ構造を扱うとき、毎回別々に型を定義していると重複が増えてしまいます。そんなときに、ジェネリクスを使うと共通化できて便利です。
2. フォームデータをジェネリクスで共通化する例
たとえば、「フォームの入力結果をまとめるオブジェクト」を共通化して扱いたいとします。以下のようなコードで、どんなフォームでも使えるようにできます。
type FormData = {
id: string;
data: T;
submittedAt: Date;
};
// ユーザー登録フォーム用
type UserForm = {
name: string;
email: string;
};
// 商品登録フォーム用
type ProductForm = {
title: string;
price: number;
};
// 使用例
const userFormData: FormData<UserForm> = {
id: "u001",
data: { name: "太郎", email: "taro@example.com" },
submittedAt: new Date(),
};
const productFormData: FormData<ProductForm> = {
id: "p001",
data: { title: "ノートPC", price: 120000 },
submittedAt: new Date(),
};
このように、<T> の部分に「型の引数」を渡して使います。FormData<UserForm>やFormData<ProductForm>のように書くことで、それぞれのフォームに応じた型を安全に扱うことができます。
3. APIレスポンスの型を汎用化して使う
次に、APIからデータを取得する場面でもジェネリクスは大活躍します。
サーバーから返ってくるデータ構造が似ている場合、毎回型を作るのは大変ですよね。そんなときに共通のレスポンス型をジェネリクスで定義します。
type ApiResponse = {
success: boolean;
message: string;
data: T;
};
// ユーザー情報APIの例
type User = {
id: number;
name: string;
};
// 商品情報APIの例
type Product = {
id: number;
title: string;
price: number;
};
// 使用例
const userResponse: ApiResponse<User> = {
success: true,
message: "ユーザー情報取得成功",
data: { id: 1, name: "花子" },
};
const productResponse: ApiResponse<Product> = {
success: true,
message: "商品情報取得成功",
data: { id: 10, title: "キーボード", price: 3500 },
};
ApiResponseの中身は同じですが、Tの部分を変えるだけで、どんな種類のレスポンスでも対応できます。
これによって、コードの再利用性がぐっと上がり、保守性も良くなります。
4. 関数でもジェネリクスを使ってみよう
ジェネリクスは型だけでなく、関数にも使うことができます。
たとえば、APIレスポンスを処理する共通関数を作るときに便利です。
function handleResponse<T>(response: ApiResponse<T>): void {
if (response.success) {
console.log("成功:", response.data);
} else {
console.error("失敗:", response.message);
}
}
handleResponse(userResponse);
handleResponse(productResponse);
このように書くことで、どんなデータ型でも安全に扱える関数が完成します。関数に渡されるデータの型が自動的に推論されるため、型ミスを防げます。
5. 実践的な使い方:フォーム入力のバリデーション
さらに一歩進んだ使い方として、フォーム入力のバリデーション(入力内容のチェック)もジェネリクスを使って共通化できます。
function validateForm<T>(form: FormData<T>): boolean {
if (!form.id || !form.data) {
console.error("フォームのデータが正しくありません");
return false;
}
console.log("フォームデータが正しい形式です");
return true;
}
validateForm(userFormData);
validateForm(productFormData);
このように、型の部分だけを入れ替えることで、どんな種類のフォームでも共通の関数でチェックできるようになります。これがジェネリクスの最大の強みです。
6. ジェネリクスで型の再利用性を高めよう
TypeScriptでフォームやAPIレスポンスを扱うとき、ジェネリクスを使えば「一つの型を何度も再利用」できます。
開発の効率が上がるだけでなく、型安全(型が正しいことを保証)なコードを書くことができます。ジェネリクスは最初は少し難しく感じますが、「型を後から指定できる便利な仕組み」と覚えておくと理解しやすいですよ。
まとめ
TypeScriptのジェネリクスについて学んできました。ジェネリクスとは「型を後から指定できる仕組み」で、フォームデータやAPIレスポンス、関数の引数、オブジェクトなど、様々な場面で共通の型を汎用的に使い回すことができます。これにより、コードの再利用性が高まり、同じ構造のデータを何度も書く必要がなくなります。さらに、型安全性も確保できるため、間違った型のデータを扱うリスクを減らせます。
フォームデータの場合、FormData<T>のように型の引数を渡すことで、ユーザー登録フォームや商品登録フォームなど、異なるデータ構造でも共通の型を使い回せます。また、APIレスポンスではApiResponse<T>のように定義することで、取得するデータの型を後から指定でき、関数に渡すときも安全に扱えます。これにより、開発効率が上がるだけでなく、コードレビューや保守の際にもわかりやすくなります。
関数にジェネリクスを使う場合も、データ型が自動で推論されるため、型ミスやバグを未然に防げます。さらに、フォームのバリデーションなど、入力チェックを共通化することで、どんな種類のフォームでも同じ関数で安全に処理できます。このように、ジェネリクスを活用することで、TypeScriptのコードはより安全で効率的に書けるようになります。
ジェネリクスの具体例
// 汎用フォーム型
type FormData<T> = {
id: string;
data: T;
submittedAt: Date;
};
// 共通バリデーション関数
function validateForm<T>(form: FormData<T>): boolean {
if (!form.id || !form.data) {
console.error("フォームのデータが正しくありません");
return false;
}
console.log("フォームデータが正しい形式です");
return true;
}
// 使用例
type UserForm = { name: string; email: string; };
const userForm: FormData<UserForm> = { id: "u001", data: { name: "太郎", email: "taro@example.com" }, submittedAt: new Date() };
validateForm(userForm);
生徒
「ジェネリクスを使うと、同じ型を何度も書かなくていいからすごく便利ですね。フォームもAPIレスポンスも、共通化できるんですね。」
先生
「その通りです。ジェネリクスを使えば、どんな型のデータにも対応できる汎用性の高いコードが書けます。さらに型安全性も確保できるので、バグを減らす効果もあります。」
生徒
「関数にも使えるから、どのフォームやAPIレスポンスでも同じ関数で処理できるんですね。型の引数を入れるだけで便利に使えるんだ。」
先生
「その通りです。最初は少し難しく感じるかもしれませんが、型を共通化して再利用する考え方を覚えると、TypeScriptでの開発が格段に効率よくなります。学んだことを実際にプロジェクトで試してみてください。」