サイトアイコンmaita tomoya dev io

TypeScript

frontend-languages

TypeScript

はじめに

TypeScriptは、JavaScriptに静的型付けを追加したプログラミング言語です。Microsoftが2012年に開発し、現在ではフロントエンド・バックエンド問わず、多くのプロジェクトで採用されています。

「JavaScriptは知っているけど、TypeScriptに移行すべきか迷っている」という方に向けて、技術選定の観点からTypeScriptの特徴を徹底的に解説します。


TypeScriptとは

基本的な位置づけ

TypeScriptはJavaScriptのスーパーセット(上位互換) です。つまり、全てのJavaScriptコードは有効なTypeScriptコードです。

+-------------------------------------------+
|                                           |
|   TypeScript                              |
|   +-----------------------------------+   |
|   |                                   |   |
|   |   JavaScript                      |   |
|   |   (全てのJS文法が使える)          |   |
|   |                                   |   |
|   +-----------------------------------+   |
|                                           |
|   + 型アノテーション                       |
|   + インターフェース                       |
|   + ジェネリクス                           |
|   + Enum                                  |
|   + デコレータ                             |
|   + etc.                                  |
|                                           |
+-------------------------------------------+

コンパイルの流れ

TypeScript (.ts / .tsx)
    |
    v
+-------------------+
| TypeScriptコンパイラ|  ← 型チェック + トランスパイル
| (tsc)              |
+-------------------+
    |
    v
JavaScript (.js / .jsx)  ← ブラウザ/Node.jsで実行可能

TypeScriptのコードは最終的にJavaScriptに変換されて実行されます。型情報は実行時には存在しません(型消去 / Type Erasure)。


JavaScript vs TypeScript 比較表

項目JavaScriptTypeScript
型システム動的型付け静的型付け(+ 動的型付け)
型チェック実行時コンパイル時
コンパイル不要(インタプリタ)必要(tsc → JS)
学習コスト低い中程度(JSの知識 + 型システム)
IDE支援基本的な補完高度な補完・リファクタリング
エラー検出実行時に発見コーディング時に発見
開発元Ecma International(標準化団体)Microsoft
初リリース1995年2012年
実行環境ブラウザ、Node.jsコンパイル後JSとして実行
ファイル拡張子.js, .jsx.ts, .tsx
パッケージそのまま使える@types/* が必要な場合あり
設定ファイル不要tsconfig.json
大規模開発困難(型がないため)適している
プロトタイプ最速やや遅い(型定義の手間)

コード比較

JavaScript:

// 関数の引数と戻り値の型が不明確
function calculateTotal(items) {
  return items.reduce((sum, item) => sum + item.price * item.quantity, 0)
}

// 呼び出し時に間違いに気づかない
const total = calculateTotal('not an array') // 実行時エラー

TypeScript:

// 型が明確に定義されている
interface CartItem {
  name: string
  price: number
  quantity: number
}

function calculateTotal(items: CartItem[]): number {
  return items.reduce((sum, item) => sum + item.price * item.quantity, 0)
}

// コンパイル時にエラーを検出
const total = calculateTotal('not an array')
// エラー: Argument of type 'string' is not assignable to parameter of type 'CartItem[]'

強み

1. 型安全性

TypeScriptの最大の強みは、コンパイル時に型エラーを検出できることです。

// バグの早期発見
interface User {
  id: number
  name: string
  email: string
  isActive: boolean
}

function sendEmail(user: User): void {
  // user.emaill ← タイプミスをコンパイル時に検出
  // Property 'emaill' does not exist on type 'User'. Did you mean 'email'?
  console.log(`Sending email to ${user.email}`)
}

// Union型による安全な分岐
type Status = 'pending' | 'approved' | 'rejected'

function handleStatus(status: Status): string {
  switch (status) {
    case 'pending':
      return '審査中です'
    case 'approved':
      return '承認されました'
    case 'rejected':
      return '却下されました'
    // "accepted" など存在しない値を書くとエラー
  }
}

2. IDE補完の劇的な改善

JavaScriptの場合:
  user.  ← 候補が表示されない(userの型が不明)

TypeScriptの場合:
  user.  ← id, name, email, isActive が候補として表示される
         ← 各プロパティの型情報も表示される
         ← 存在しないプロパティへのアクセスは赤線で警告

これは開発速度に直結します。特に以下の場面で効果を発揮します:

  • 他人が書いたコードを理解するとき
  • APIのレスポンス構造を確認するとき
  • ライブラリの使い方を調べるとき

3. リファクタリングの安全性

例: プロパティ名の変更

  User.name → User.displayName に変更したい場合

  JavaScript:
    - 全ファイルを検索して手動で置換
    - 見落としがあると実行時エラー
    - テストを全て通しても漏れがある可能性

  TypeScript:
    - IDEの「名前の変更」機能で一括変更
    - 変更漏れがあればコンパイルエラー
    - 全ての参照箇所が自動的に更新される

4. 大規模開発での真価

プロジェクト規模と型システムの価値:

型システムの価値
  ^
  |                                    *
  |                                *
  |                            *
  |                        *
  |                    *
  |                *
  |            *
  |        *
  |    *
  | *
  +-----------------------------------------> プロジェクト規模
  1人      5人     10人    20人    50人+

  小規模: 型定義の手間 > メリット(場合がある)
  中規模: 型定義のメリットが手間を上回り始める
  大規模: 型がないと破綻する

5. ドキュメントとしての型

// 型定義がそのままドキュメントになる
interface CreateOrderRequest {
  /** 顧客ID */
  customerId: string
  /** 注文アイテムのリスト(1件以上) */
  items: OrderItem[]
  /** 配送先住所 */
  shippingAddress: Address
  /** 支払い方法 */
  paymentMethod: 'credit_card' | 'bank_transfer' | 'convenience_store'
  /** クーポンコード(任意) */
  couponCode?: string
}

// この型定義を見れば、APIに何を渡せばいいか一目瞭然

弱み

1. 学習コスト

TypeScriptの型システムは非常に強力ですが、その分複雑です。

// 初心者が混乱しやすい型の例

// ジェネリクス
function identity<T>(arg: T): T {
  return arg
}

// Conditional Types
type IsString<T> = T extends string ? true : false

// Mapped Types
type Readonly<T> = {
  readonly [P in keyof T]: T[P]
}

// Template Literal Types
type EventName = `on${Capitalize<string>}`

// Infer
type ReturnType<T> = T extends (...args: any[]) => infer R ? R : never

学習の段階

レベル1(1〜2週間): 基本的な型アノテーション
  - string, number, boolean
  - 配列、オブジェクト型
  - 関数の引数と戻り値の型

レベル2(1〜2ヶ月): 中級的な型
  - interface と type の使い分け
  - Union型、Intersection型
  - ジェネリクスの基本
  - 型ガード

レベル3(3〜6ヶ月): 高度な型
  - Conditional Types
  - Mapped Types
  - Template Literal Types
  - infer キーワード

レベル4(6ヶ月〜): 型プログラミング
  - 再帰型
  - 型レベルの計算
  - 複雑なユーティリティ型の実装

2. コンパイル時間

プロジェクトが大きくなると、型チェックに時間がかかるようになります。

プロジェクト規模型チェック時間(目安)
小規模(〜100ファイル)1〜3秒
中規模(〜1,000ファイル)5〜15秒
大規模(〜10,000ファイル)30秒〜数分

対策:

  • Project Referencesで分割ビルド
  • incrementalオプションで差分ビルド
  • esbuild、swcなど高速トランスパイラの活用(型チェックはtscで別途実行)

3. 型定義の複雑さ

サードパーティライブラリの型定義(@types/*)が不正確だったり、存在しない場合があります。

// 型定義がないライブラリを使う場合
// @ts-ignore や any を使わざるを得ない場面がある

// 解決策1: 自分で型定義を書く
declare module 'untyped-library' {
  export function doSomething(input: string): number
}

// 解決策2: any で逃げる(非推奨だが現実的な場面もある)
const result = (untypedLib as any).doSomething('hello')

4. 実行時の型保証がない

TypeScriptの型はコンパイル時にのみ存在し、実行時には消えます。

// 外部からのデータ(API、ユーザー入力等)には型保証がない
interface UserResponse {
  id: number
  name: string
}

// APIレスポンスをUserResponseとして扱うが、実際の中身は保証されない
const response: UserResponse = await fetch('/api/user').then((r) => r.json())
// response.nameがundefinedでも、TypeScriptはエラーを出さない

// 解決策: zodなどのバリデーションライブラリを使う
import { z } from 'zod'

const UserSchema = z.object({
  id: z.number(),
  name: z.string(),
})

const validatedResponse = UserSchema.parse(await fetch('/api/user').then((r) => r.json()))
// 実行時にバリデーションされる

JSから移行すべきかの判断基準

移行すべきケース

条件理由
チーム開発(3人以上)型がコミュニケーションツールになる
コードベースが10,000行以上リファクタリングの安全性が必要
APIの型定義が複雑型で構造を明確にできる
バグの頻度が高い型チェックでバグを事前に防げる
長期間メンテナンスが必要型がドキュメントとして機能する

移行しなくてよいケース

条件理由
個人の小規模プロジェクト型定義のオーバーヘッドが大きい
短期間のプロトタイプスピードが最優先
チーム全員がTS未経験学習コストがプロジェクトに影響
スクリプト的な使い方数十行のスクリプトに型は過剰

判断フローチャート

プロジェクトの寿命は6ヶ月以上か?
    |
    +-- はい --> チームは2人以上か?
    |               |
    |               +-- はい --> TypeScriptを強く推奨
    |               |
    |               +-- いいえ --> コードベースは成長する予定か?
    |                               |
    |                               +-- はい --> TypeScript推奨
    |                               |
    |                               +-- いいえ --> JavaScriptでもOK
    |
    +-- いいえ --> プロトタイプ・実験的なプロジェクトか?
                    |
                    +-- はい --> JavaScriptで十分
                    |
                    +-- いいえ --> TypeScript推奨

実際のプロダクト例

Angular

Googleが開発するフロントエンドフレームワーク。Angular 2以降はTypeScriptで書かれており、TypeScriptが第一級言語として扱われています。

VS Code

MicrosoftのコードエディタであるVisual Studio Code自体がTypeScriptで開発されています。TypeScriptの開発体験を最も良く知るプロダクトの一つです。

Deno

Node.jsの開発者であるRyan DahlがTypeScriptのネイティブサポートを目的の一つとして開発したJavaScript/TypeScriptランタイムです。

Slack

SlackのデスクトップアプリはElectron + TypeScriptで開発されています。大規模なコードベースの保守性を型安全性で担保しています。

その他の採用企業

  • Airbnb: JavaScriptからTypeScriptへの大規模移行を実施
  • Shopify: フロントエンドをTypeScriptで統一
  • Bloomberg: 金融アプリケーションの信頼性のためTypeScriptを採用
  • Stripe: SDKやダッシュボードにTypeScriptを採用

採用市場での評価

TypeScriptの市場動向(2025-2026年)

TypeScriptの採用率推移(概念図)

採用率
  ^
  |                                          *
  |                                     *
  |                                *
  |                           *
  |                      *
  |                 *
  |            *
  |       *
  |   *
  | *
  +-----------------------------------------> 年
  2017  2018  2019  2020  2021  2022  2023  2024  2025  2026

  State of JS調査によると、TypeScriptの使用率は年々増加し、
  2024-2025年時点で新規プロジェクトの80%以上がTypeScriptを採用
指標状況
求人数急増中(JS求人の多くがTS必須/歓迎)
年収JSのみよりやや高い傾向
必須スキル化フロントエンド求人ではほぼ必須に
将来性JS + TSのセットが標準に

TypeScript導入の段階的アプローチ

既存のJavaScriptプロジェクトにTypeScriptを導入する際の段階的なアプローチを紹介します。

Phase 1: 最小限の導入(1〜2日)

1. tsconfig.jsonを追加
2. allowJs: true に設定(JSファイルをそのまま使える)
3. strict: false に設定(緩い型チェック)
4. 新規ファイルだけ .ts で作成
// tsconfig.json(最小限の設定)
{
  "compilerOptions": {
    "target": "ES2020",
    "module": "ESNext",
    "allowJs": true,
    "checkJs": false,
    "strict": false,
    "outDir": "./dist",
    "rootDir": "./src"
  },
  "include": ["src/**/*"]
}

Phase 2: 徐々に型を追加(1〜2ヶ月)

1. 共通の型定義ファイルを作成(types.ts)
2. 重要なファイルから順に .js → .ts に変換
3. any を使ってもOK。まずはコンパイルを通す
4. APIのレスポンス型を定義する

Phase 3: strictモードへの移行(2〜3ヶ月)

1. strict: true に変更
2. コンパイルエラーを一つずつ修正
3. any を具体的な型に置き換える
4. 型ガードを追加する

Phase 4: 完全なTypeScript化(継続的)

1. 全ファイルを .ts に変換完了
2. noImplicitAny: true(anyの暗黙的使用を禁止)
3. strictNullChecks: true(null/undefinedの厳密チェック)
4. eslintにTypeScript用のルールを追加

まとめ: TypeScriptの技術選定での位置づけ

5段階評価

評価項目スコアコメント
パフォーマンス3/5JSと同等(コンパイル後はJS)
型安全性4/5コンパイル時は強力。実行時は型消去
学習曲線3/5JS経験者なら比較的容易。型システムは深い
エコシステム5/5JSのエコシステムをそのまま利用可能
採用市場5/5フロントエンドではほぼ必須に
スケーラビリティ4/5大規模開発に適している
開発速度4/5型定義の手間はあるが、バグ検出で時間節約
保守性5/5型がドキュメントとして機能

一言でまとめると

「迷ったらTypeScript」 -- JavaScriptを選ぶ明確な理由がない限り、TypeScriptを選んだ方が後悔は少ない。


参考資料