TypeScript で型安全な API クライアントを作る

10分
TypeScript API

型安全な API クライアントの重要性

API 通信では、型の不一致によるランタイムエラーが発生しやすいです。 TypeScript の型システムを活用することで、これらのエラーを未然に防げます。

基本的な型定義

// レスポンスの型定義
interface User {
  id: number;
  name: string;
  email: string;
}

interface ApiResponse<T> {
  data: T;
  status: number;
  message?: string;
}

ジェネリックを活用した API クライアント

class ApiClient {
  private baseURL: string;

  constructor(baseURL: string) {
    this.baseURL = baseURL;
  }

  async get<T>(endpoint: string): Promise<ApiResponse<T>> {
    const response = await fetch(`${this.baseURL}${endpoint}`);
    return response.json();
  }

  async post<T, U>(endpoint: string, data: U): Promise<ApiResponse<T>> {
    const response = await fetch(`${this.baseURL}${endpoint}`, {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify(data),
    });
    return response.json();
  }
}

使用例

const client = new ApiClient('https://api.example.com');

// 型推論が効く
const response = await client.get<User[]>('/users');
console.log(response.data); // User[] 型として扱える

エラーハンドリングの型安全化

type ApiError = {
  code: string;
  message: string;
};

type Result<T> =
  | { success: true; data: T }
  | { success: false; error: ApiError };

async function fetchUser(id: number): Promise<Result<User>> {
  try {
    const response = await client.get<User>(`/users/${id}`);
    return { success: true, data: response.data };
  } catch (error) {
    return {
      success: false,
      error: { code: 'FETCH_ERROR', message: String(error) }
    };
  }
}

まとめ

TypeScript の型システムを活用することで、 API 通信の安全性と開発体験を大幅に向上させることができます。 ジェネリクスや Union Types を駆使して、堅牢な API クライアントを構築しましょう。