【2026年版】TypeScript完全ガイド|型システムの基礎から実践的なNext.js開発まで徹底解説

TypeScriptはJavaScriptに静的型付けを加えた言語として、2026年現在ほぼ全てのモダンなWeb開発プロジェクトで採用されています。この記事では、TypeScript初心者から中級者に向けて、型システムの基礎から実践的なNext.js・React開発での活用まで徹底解説します。

TypeScriptとは?JavaScriptとの違い

TypeScriptはMicrosoftが開発したJavaScriptのスーパーセットです。コンパイル時に型エラーを検出できるため、大規模なコードベースでのバグを事前に防ぐことができます。

TypeScriptを使うメリット

  • 型安全性:コンパイル時にバグを検出
  • IDE補完の強化:IntelliSenseで開発効率UP
  • リファクタリングが安全:型情報で影響範囲が明確
  • チーム開発に最適:コードの意図が型で伝わる

TypeScriptの基本型システム

プリミティブ型

// 基本的な型アノテーション
const name: string = "田中太郎";
const age: number = 25;
const isActive: boolean = true;
const nothing: null = null;
const notDefined: undefined = undefined;

// 配列型
const numbers: number[] = [1, 2, 3];
const strings: Array = ["a", "b", "c"];

// タプル型
const tuple: [string, number] = ["hello", 42];

// any型(使用は最小限に)
const anything: any = "anything goes";

インターフェースと型エイリアス

// インターフェースの定義
interface User {
  id: number;
  name: string;
  email: string;
  role: "admin" | "user" | "moderator"; // ユニオン型
  createdAt: Date;
  bio?: string; // オプショナルプロパティ
  readonly uuid: string; // 読み取り専用
}

// 型エイリアス
type ApiResponse = {
  data: T;
  status: number;
  message: string;
  timestamp: string;
};

// 使用例
const user: User = {
  id: 1,
  name: "田中太郎",
  email: "tanaka@example.com",
  role: "admin",
  createdAt: new Date(),
  uuid: "550e8400-e29b-41d4-a716-446655440000"
};

const response: ApiResponse = {
  data: user,
  status: 200,
  message: "Success",
  timestamp: new Date().toISOString()
};

ジェネリクス(Generics)

// ジェネリック関数
function getFirst(array: T[]): T | undefined {
  return array[0];
}

const firstNumber = getFirst([1, 2, 3]); // type: number | undefined
const firstString = getFirst(["a", "b"]); // type: string | undefined

// ジェネリッククラス
class Stack {
  private items: T[] = [];

  push(item: T): void {
    this.items.push(item);
  }

  pop(): T | undefined {
    return this.items.pop();
  }

  peek(): T | undefined {
    return this.items[this.items.length - 1];
  }

  get size(): number {
    return this.items.length;
  }
}

const stack = new Stack();
stack.push(1);
stack.push(2);
console.log(stack.pop()); // 2

実践的なTypeScript:React・Next.jsでの活用

Reactコンポーネントの型定義

import React, { FC, useState, useCallback } from 'react';

// Propsの型定義
interface ButtonProps {
  label: string;
  onClick: () => void;
  variant?: "primary" | "secondary" | "danger";
  disabled?: boolean;
  children?: React.ReactNode;
}

// FC(Function Component)で型付け
const Button: FC = ({
  label,
  onClick,
  variant = "primary",
  disabled = false,
  children
}) => {
  return (
    <button
      className={`btn btn-${variant}`}
      onClick={onClick}
      disabled={disabled}
    >
      {children || label}
    </button>
  );
};

// カスタムフックの型付け
function useCounter(initialValue: number = 0) {
  const [count, setCount] = useState<number>(initialValue);

  const increment = useCallback(() => setCount(c => c + 1), []);
  const decrement = useCallback(() => setCount(c => c - 1), []);
  const reset = useCallback(() => setCount(initialValue), [initialValue]);

  return { count, increment, decrement, reset };
}

Next.jsでのAPI Routeの型付け

// app/api/users/route.ts (Next.js App Router)
import { NextRequest, NextResponse } from 'next/server';

interface UserCreateRequest {
  name: string;
  email: string;
  role: "admin" | "user";
}

export async function GET(request: NextRequest) {
  const searchParams = request.nextUrl.searchParams;
  const page = Number(searchParams.get('page') || 1);

  try {
    const users = await prisma.user.findMany({
      skip: (page - 1) * 10,
      take: 10,
      orderBy: { createdAt: 'desc' }
    });

    return NextResponse.json({
      data: users,
      page,
      total: await prisma.user.count()
    });
  } catch (error) {
    return NextResponse.json(
      { error: 'Internal Server Error' },
      { status: 500 }
    );
  }
}

export async function POST(request: NextRequest) {
  const body: UserCreateRequest = await request.json();

  if (!body.name || !body.email) {
    return NextResponse.json(
      { error: 'Name and email are required' },
      { status: 400 }
    );
  }

  const user = await prisma.user.create({
    data: body
  });

  return NextResponse.json(user, { status: 201 });
}

TypeScriptの高度な型テクニック

Utility Types

interface Product {
  id: number;
  name: string;
  price: number;
  description: string;
  stock: number;
}

// Partial:すべてのプロパティをオプショナルに
type UpdateProduct = Partial<Product>;

// Required:すべてのプロパティを必須に
type RequiredProduct = Required<Product>;

// Pick:特定のプロパティのみ選択
type ProductSummary = Pick<Product, "id" | "name" | "price">;

// Omit:特定のプロパティを除外
type CreateProduct = Omit<Product, "id">;

// Readonly:すべてのプロパティを読み取り専用に
type ImmutableProduct = Readonly<Product>;

// Record:キーと値の型を指定したオブジェクト
type CategoryProducts = Record<string, Product[]>;

TypeScript設定ファイル(tsconfig.json)のベストプラクティス

{
  "compilerOptions": {
    "target": "ES2022",
    "lib": ["ES2022", "DOM", "DOM.Iterable"],
    "module": "ESNext",
    "moduleResolution": "bundler",
    "strict": true,              // 厳格モードを有効化
    "noImplicitAny": true,       // 暗黙的なany型を禁止
    "strictNullChecks": true,    // nullチェックを厳格に
    "noUnusedLocals": true,      // 未使用のローカル変数を検出
    "noUnusedParameters": true,  // 未使用のパラメータを検出
    "noImplicitReturns": true,   // 全コードパスでreturnを強制
    "esModuleInterop": true,
    "skipLibCheck": true,
    "forceConsistentCasingInFileNames": true,
    "outDir": "./dist",
    "rootDir": "./src",
    "baseUrl": ".",
    "paths": {
      "@/*": ["./src/*"]
    }
  },
  "include": ["src/**/*"],
  "exclude": ["node_modules", "dist"]
}

まとめ:TypeScriptで型安全な開発を実現しよう

TypeScriptをマスターすることで、開発効率と品質が大幅に向上します。最初は型エラーに戸惑うかもしれませんが、慣れると型の恩恵を強く感じるようになります。Reactエコシステムとの相性も抜群なので、Next.js開発と組み合わせて実践的なプロジェクトで習得を進めましょう。

投稿者 kasata

IT企業でエンジニアとして勤務後、テクノロジー情報メディア「Tech Athletes(テック・アスリート)」を運営。プログラミング、クラウドインフラ(AWS/GCP/Azure)、AI活用、Webサービス開発を専門とする。エンジニア・ビジネスパーソン向けに、実際に使ってみた経験をもとに信頼できる技術情報を発信中。資格:AWS認定ソリューションアーキテクト、Python 3 エンジニア認定試験合格。

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です