この記事でわかること: TypeScriptの型システムの基礎からジェネリクス・型推論・高度な型操作まで、JavaScriptエンジニアが実務でTypeScriptを使いこなすための完全ガイドです。React・Node.jsでの実践的な使い方もカバーします。
TypeScriptとは?JavaScriptとの違い
TypeScriptはMicrosoftが開発したJavaScriptのスーパーセット(上位互換)です。JavaScriptに静的型付けを追加することで、コンパイル時にエラーを検出でき、大規模なアプリケーション開発の生産性と安全性を大幅に向上させます。
| 特徴 | JavaScript | TypeScript |
|---|---|---|
| 型システム | 動的型付け | 静的型付け |
| エラー検出 | 実行時 | コンパイル時 |
| IDE補完 | 限定的 | 強力(IntelliSense) |
| リファクタリング | 困難 | 安全・容易 |
| 学習コスト | 低い | やや高い(型の学習が必要) |
| 本番環境 | そのまま実行 | JavaScriptにトランスパイル |
TypeScriptのセットアップ
# Node.jsとnpmが必要
npm install -g typescript
# バージョン確認
tsc --version
# Version 5.x.x
# プロジェクトの初期化
mkdir my-ts-project && cd my-ts-project
npm init -y
npm install typescript --save-dev
# tsconfig.jsonを生成
npx tsc --init
おすすめのtsconfig.json設定(2026年版):
{
"compilerOptions": {
"target": "ES2022",
"lib": ["ES2022", "DOM"],
"module": "ESNext",
"moduleResolution": "bundler",
"strict": true,
"noUncheckedIndexedAccess": true,
"noImplicitOverride": true,
"exactOptionalPropertyTypes": true,
"outDir": "./dist",
"rootDir": "./src",
"declaration": true,
"sourceMap": true,
"skipLibCheck": true
},
"include": ["src/**/*"],
"exclude": ["node_modules", "dist"]
}
基本の型アノテーション
// プリミティブ型
const name: string = "田中太郎";
const age: number = 30;
const isActive: boolean = true;
const nothing: null = null;
const undef: undefined = undefined;
// 配列
const scores: number[] = [85, 92, 78];
const names: Array = ["Alice", "Bob", "Charlie"];
// タプル(固定長配列)
const point: [number, number] = [10, 20];
const record: [string, number, boolean] = ["Alice", 30, true];
// オブジェクト型
const user: { name: string; age: number; email?: string } = {
name: "田中太郎",
age: 30,
// emailはオプショナル(?)なので省略可能
};
// Union型(複数の型のいずれか)
let id: string | number = "user-123";
id = 456; // OK
// Literal型(特定の値のみ許可)
type Direction = "north" | "south" | "east" | "west";
type HttpStatus = 200 | 201 | 400 | 401 | 403 | 404 | 500;
interfaceとtypeの使い分け
// interface:オブジェクト型の定義に主に使用、拡張が容易
interface User {
id: number;
name: string;
email: string;
createdAt: Date;
}
// interfaceの継承
interface AdminUser extends User {
role: "admin" | "superadmin";
permissions: string[];
}
// type:より汎用的、Union型やMapped型にも使える
type Point = {
x: number;
y: number;
};
// Intersection型(複数の型を組み合わせ)
type UserWithProfile = User & {
avatar: string;
bio: string;
};
// 使い分けの目安
// - interfaceを使う場面:クラスやオブジェクトの構造定義、拡張性が必要な場合
// - typeを使う場面:Union型、Intersection型、型エイリアス、プリミティブ型の別名
ジェネリクス(Generics)の活用
ジェネリクスは型安全性を保ちながら汎用的なコードを書くための最重要機能です。
// 基本的なジェネリクス関数
function identity(arg: T): T {
return arg;
}
// ジェネリクス制約(extends)
function getProperty(obj: T, key: K): T[K] {
return obj[key];
}
const user = { name: "Alice", age: 30 };
const name = getProperty(user, "name"); // string
const age = getProperty(user, "age"); // number
// ジェネリクスのある型定義
interface ApiResponse {
data: T;
status: number;
message: string;
timestamp: Date;
}
interface Product {
id: number;
name: string;
price: number;
}
// 使用例
const productResponse: ApiResponse = {
data: { id: 1, name: "MacBook Pro", price: 398000 },
status: 200,
message: "Success",
timestamp: new Date(),
};
const productListResponse: ApiResponse = {
data: [
{ id: 1, name: "MacBook Pro", price: 398000 },
{ id: 2, name: "iPhone 17", price: 149800 },
],
status: 200,
message: "Success",
timestamp: new Date(),
};
Utility Types(ユーティリティ型)
TypeScript組み込みのユーティリティ型を使うと、既存の型から新しい型を効率的に作成できます。
interface User {
id: number;
name: string;
email: string;
password: string;
createdAt: Date;
}
// Partial: すべてのプロパティをオプショナルに
type UpdateUserInput = Partial;
// { id?: number; name?: string; email?: string; ... }
// Required: すべてのプロパティを必須に
type RequiredUser = Required;
// Readonly: すべてのプロパティを読み取り専用に
type ReadonlyUser = Readonly;
// Pick: 指定したプロパティのみを持つ型
type UserPublicProfile = Pick;
// { id: number; name: string; email: string }
// Omit: 指定したプロパティを除いた型
type UserWithoutPassword = Omit;
// { id: number; name: string; email: string; createdAt: Date }
// Record: キーと値の型を指定したオブジェクト型
type UserMap = Record;
type StatusMessages = Record;
// ReturnType: 関数の戻り値型を取得
function createUser(name: string, email: string) {
return { id: Math.random(), name, email, createdAt: new Date() };
}
type CreatedUser = ReturnType;
// Awaited: Promiseの解決型を取得
type AsyncUser = Awaited>; // User
ReactでのTypeScript実践例
import React, { useState, useCallback, FC } from 'react';
// PropsのInterface定義
interface ButtonProps {
label: string;
onClick: () => void;
variant?: 'primary' | 'secondary' | 'danger';
disabled?: boolean;
className?: string;
}
// FC(Function Component)で型付け
const Button: FC = ({
label,
onClick,
variant = 'primary',
disabled = false,
className = ''
}) => {
return (
);
};
// Custom Hookの型付け
function useCounter(initialValue: number = 0) {
const [count, setCount] = useState(initialValue);
const increment = useCallback(() => setCount(prev => prev + 1), []);
const decrement = useCallback(() => setCount(prev => prev - 1), []);
const reset = useCallback(() => setCount(initialValue), [initialValue]);
return { count, increment, decrement, reset };
}
// 使用例
const Counter: FC = () => {
const { count, increment, decrement, reset } = useCounter(0);
return (
Count: {count}
);
};
TypeScriptのベストプラクティス
- strictモードを有効にする:
tsconfig.jsonで"strict": trueを設定して、潜在的なバグを早期に検出する - anyを避ける:
anyは型安全性を破壊するので、unknownまたは具体的な型を使う - 型推論を活かす:TypeScriptが型を推論できる場合は明示的なアノテーションを省略して可読性を向上させる
- enumよりconst assertionを使う:
as constでリテラル型を作成するほうが軽量でツリーシェイキングにも有利 - Zodで実行時型検証:APIレスポンスなど外部データの検証にはZodライブラリを活用する
まとめ:TypeScriptでより安全な開発を
TypeScriptは2026年の現代においてフロントエンド・バックエンドを問わず事実上の標準となっています。
- ✅ 基本型: string, number, boolean, null, undefined, Array, tuple
- ✅ Union/Intersection型: 柔軟な型定義が可能
- ✅ interface/type: オブジェクト構造の定義
- ✅ Generics: 型安全な汎用コードの実現
- ✅ Utility Types: Partial, Pick, Omit, Readonlyなどで型変換
- ✅ Reactとの組み合わせ: Props・State・Custom Hookの型付け
まずは既存のJavaScriptプロジェクトに徐々にTypeScriptを導入し、strictモードへの移行を目指しましょう。型の恩恵を実感するほど、TypeScriptなしの開発が不安に感じられるようになるはずです。