TypeScriptの型システムを理解して堅牢なコードを書く


TypeScriptの型システムとは

TypeScriptは、JavaScriptに静的型付けを追加した言語です。型システムを活用することで、コンパイル時にエラーを検出し、より安全なコードを書くことができます。

基本的な型

プリミティブ型

// 基本的な型
let name: string = "太郎";
let age: number = 25;
let isActive: boolean = true;
let value: null = null;
let data: undefined = undefined;

配列とタプル

// 配列
let numbers: number[] = [1, 2, 3, 4, 5];
let names: Array<string> = ["太郎", "花子"];

// タプル(固定長の配列)
let user: [string, number] = ["太郎", 25];

オブジェクトの型定義

Interface

interface User {
  id: number;
  name: string;
  email: string;
  age?: number; // オプショナル
}

const user: User = {
  id: 1,
  name: "太郎",
  email: "taro@example.com"
};

Type Alias

type Point = {
  x: number;
  y: number;
};

type ID = string | number; // Union型

高度な型

ジェネリクス

型を引数として受け取ることで、再利用可能な型定義を作成できます:

// ジェネリック関数
function identity<T>(arg: T): T {
  return arg;
}

const result1 = identity<string>("hello");
const result2 = identity<number>(42);

// ジェネリックインターフェース
interface Response<T> {
  data: T;
  status: number;
  message: string;
}

const userResponse: Response<User> = {
  data: { id: 1, name: "太郎", email: "taro@example.com" },
  status: 200,
  message: "Success"
};

ユーティリティ型

TypeScriptには便利なユーティリティ型が組み込まれています:

// Partial - すべてのプロパティをオプショナルに
type PartialUser = Partial<User>;

// Required - すべてのプロパティを必須に
type RequiredUser = Required<User>;

// Pick - 特定のプロパティのみ選択
type UserPreview = Pick<User, 'id' | 'name'>;

// Omit - 特定のプロパティを除外
type UserWithoutEmail = Omit<User, 'email'>;

// Record - キーと値の型を指定
type UserMap = Record<string, User>;

型ガード

型を絞り込むためのテクニック:

function isString(value: unknown): value is string {
  return typeof value === 'string';
}

function processValue(value: string | number) {
  if (isString(value)) {
    // この中ではvalueはstring型
    console.log(value.toUpperCase());
  } else {
    // この中ではvalueはnumber型
    console.log(value.toFixed(2));
  }
}

実践的なパターン

APIレスポンスの型定義

interface ApiResponse<T> {
  success: boolean;
  data?: T;
  error?: {
    code: string;
    message: string;
  };
}

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

まとめ

TypeScriptの型システムを活用することで、より安全で保守性の高いコードを書くことができます。最初は複雑に感じるかもしれませんが、慣れてくると型による恩恵を実感できるはずです。

型定義を丁寧に行うことで、IDEの補完機能も強化され、開発効率も向上します。ぜひ積極的に型を活用してみてください!