【無料配布】10日間で学べるTypeScript学習資料

TypeScriptでAPI開発!型安全な実装からデータ取得まで徹底解説

目次

API開発においてTypeScriptが最強である理由

モダンなWeb開発において、APIは「データの運び屋」です。

しかし、JavaScriptでAPIを扱う際、多くのエンジニアが「届いたデータが実はundefinedだった」「プロパティ名が1文字違っていてアプリがクラッシュした」という、いわゆるランタイムエラーの悪夢に悩まされてきました。

TypeScriptをAPI開発に導入する最大のメリットは、「通信の契約」をコードとして定義できる点にあります。

APIが何を返し、サーバーが何を求めているのかを「型」という名のドキュメントとして共有することで、フロントエンドとバックエンドの齟齬をなくし、開発速度と安全性を爆発的に高めることができます。

外部APIを型安全にコールする技術

フロントエンドからAPIを叩く際、最も危険なのは「何が返ってくるかわからない any」の状態でデータを扱うことです。

Fetch APIとinterfaceによる基本的な型定義

ブラウザ標準の fetch を使う場合、戻り値の型はデフォルトで anyunknown になります。

ここで、期待するデータの形を interface で定義し、型アサーション(as)やジェネリクスを活用しましょう。

interface UserResponse {
  id: number;
  name: string;
  email: string;
}

async function getUser(id: number): Promise<UserResponse> {
  const response = await fetch(`https://api.example.com/users/${id}`);
  // ここで型を指定する
  const data = (await response.json()) as UserResponse;
  return data;
}

ただし、as は「TypeScriptを信じ込ませる」行為です。

実際のAPIレスポンスが定義と異なれば、実行時にエラーが出ます。

この「信頼のギャップ」を埋める方法は第4章で詳述します。

Axiosを活用したスマートな型管理

実務で人気の Axios は、ジェネリクスを標準サポートしており、より直感的に型を付与できます。

import axios from 'axios';

const { data } = await axios.get<UserResponse>('/users/1');
// data は自動的に UserResponse 型として扱われる

サーバーサイドでの型安全なエンドポイント構築

Node.jsでAPIサーバーを作る際も、TypeScriptは絶大な威力を発揮します。

ExpressとTypeScriptの組み合わせ

世界で最も使われている Express ですが、素のままではリクエストボディ(req.body)などの型が曖昧です。

@types/express を導入し、リクエストのジェネリクスを活用しましょう。

import { Request, Response } from 'express';

interface CreateUserDto {
  name: string;
  age: number;
}

app.post('/users', (req: Request<{}, {}, CreateUserDto>, res: Response) => {
  const { name, age } = req.body; // 型補完が効く
  res.status(201).json({ message: `${name} created.` });
});

NestJSで実現するエンタープライズ級のAPI設計

より大規模なAPI開発には NestJS が推奨されます。

Decoratorを用いたDI(依存性の注入)や、DTO(Data Transfer Object)クラスによって、APIの仕様と型定義を完全に同期させることができます。

Zodによるランタイムバリデーション

本記事で最も伝えたい「TypeScript API」開発の核心です。

「型がある」と「正しいデータが来る」は別物

TypeScriptの型はコンパイル時に消滅します。

つまり、APIから「期待とは違うゴミデータ」が届いた場合、TypeScriptはそれを防げません。

これを解決するのが「ランタイムバリデーション」です。

Zodでスキーマ駆動開発を取り入れる

Zod を使うと、スキーマ(データの定義)から自動的にTypeScriptの型を生成しつつ、実行時にデータの検証も行えます。

import { z } from 'zod';

const UserSchema = z.object({
  id: z.number(),
  name: z.string(),
  email: z.string().email(), // メアドの形式までチェック
});

// スキーマから型を抽出
type User = z.infer<typeof UserSchema>;

async function safeGetUser(id: number) {
  const res = await fetch(`/api/users/${id}`);
  const rawData = await res.json();
  
  // 実行時に検証!ダメならここでエラーを投げる
  const result = UserSchema.safeParse(rawData);
  
  if (!result.success) {
    throw new Error("APIのデータ形式が不正です");
  }
  
  return result.data; // ここでは 100% 安全な User 型
}

End-to-End Type Safety(Hono / tRPC)

2026年現在のトレンドは、フロントエンドとバックエンドの境界をなくす End-to-End (E2E) Type Safety です。

tRPC

API定義そのものを型として共有し、フロントエンド側で「サーバーの関数を直接叩く」ような感覚で、一度も interface を書かずに完全な型安全を実現します。

Hono

超軽量なWebフレームワークでありながら、hono/client を使うことで、サーバー側のルーティング定義をフロントエンドが再利用でき、APIパスの入力ミスすらコンパイルエラーで防げます。

TypeScriptで堅牢なAPIエコシステムを構築する

「TypeScript api」というテーマを攻略するための鍵は、単に interface を書くことではありません。

堅牢なAPIエコシステム
  • 取得時: as に頼らず、ジェネリクスを活用する
  • 作成時: フレームワークの型定義を最大限活用し、DTOを徹底する
  • 信頼性: Zod などのバリデーターで、型と実データを同期させる
  • 効率化: 可能であれば HonotRPC で型を共有する

これらを意識するだけで、API起因のバグは劇的に減り、開発チーム全体の「安心感」になります。

型安全なAPI開発は必須条件です。

よかったらシェアしてね!
  • URLをコピーしました!
  • URLをコピーしました!
目次