console (TypeScript)

TypeScript/JavaScript標準のコンソール出力API。型安全な使用が可能で、開発・デバッグ段階での迅速なログ出力に適している。設定不要で即座に利用可能だが、本番環境では機能制限がある。

console

consoleオブジェクトは、TypeScript/JavaScriptの標準APIとして提供されるログ出力機能です。開発時のデバッグから本番環境でのエラー追跡まで、幅広い用途で使用されます。ブラウザとNode.jsの両環境で利用可能です。

主な特徴

  • 標準API - 追加のライブラリ不要
  • 多様なメソッド - 用途別の豊富なログメソッド
  • 視覚的な出力 - テーブル表示やグループ化
  • パフォーマンス測定 - タイマー機能
  • スタックトレース - エラー追跡機能

基本的な使い方

主要なログメソッド

// 一般的な情報出力
console.log("アプリケーションが起動しました");

// エラー(多くの環境で赤色表示)
console.error("エラーが発生しました:", new Error("データベース接続失敗"));

// 警告(多くの環境で黄色表示)
console.warn("非推奨のAPIを使用しています");

// 情報メッセージ
console.info("ユーザー登録が完了しました");

// デバッグメッセージ(ブラウザでは詳細レベルの設定が必要)
console.debug("デバッグ情報:", { userId: 123, action: "login" });

複数の値の出力

const user = { id: 1, name: "田中太郎" };
const score = 95;

// 複数の値を一度に出力
console.log("ユーザー:", user, "スコア:", score);

// オブジェクトの展開表示
console.log({ user, score });

// 文字列テンプレート
console.log(`${user.name}のスコアは${score}点です`);

高度なログメソッド

テーブル表示

// 配列のテーブル表示
const users = [
  { id: 1, name: "田中", age: 25, role: "管理者" },
  { id: 2, name: "鈴木", age: 30, role: "ユーザー" },
  { id: 3, name: "佐藤", age: 28, role: "ユーザー" }
];

console.table(users);

// 特定のカラムのみ表示
console.table(users, ["name", "role"]);

// オブジェクトのテーブル表示
const stats = {
  total: 100,
  success: 85,
  failed: 15,
  pending: 0
};

console.table(stats);

グループ化

console.group("ユーザー認証プロセス");
console.log("1. 認証情報を検証");
console.log("2. トークンを生成");
console.log("3. セッションを作成");
console.groupEnd();

// 折りたたみ可能なグループ
console.groupCollapsed("詳細ログ");
console.log("詳細情報1");
console.log("詳細情報2");
console.groupEnd();

// ネストされたグループ
console.group("API呼び出し");
console.log("エンドポイント: /api/users");
console.group("リクエスト");
console.log("メソッド: GET");
console.log("ヘッダー: Authorization: Bearer xxx");
console.groupEnd();
console.group("レスポンス");
console.log("ステータス: 200");
console.log("データ: [...]");
console.groupEnd();
console.groupEnd();

パフォーマンス測定

// 処理時間の測定
console.time("データ処理");

// 重い処理
const result = processLargeDataSet();

console.timeEnd("データ処理"); // 出力: データ処理: 123.456ms

// 複数のタイマーを同時に使用
console.time("全体処理");
console.time("データベース");
await fetchFromDatabase();
console.timeEnd("データベース");

console.time("計算処理");
await performCalculations();
console.timeEnd("計算処理");
console.timeEnd("全体処理");

// タイムログ(途中経過を出力)
console.time("プロセス");
console.timeLog("プロセス", "初期化完了");
// ... 処理 ...
console.timeLog("プロセス", "データ読み込み完了");
// ... 処理 ...
console.timeEnd("プロセス");

アサーションとカウント

// アサーション(条件が偽の場合のみ出力)
const age = 15;
console.assert(age >= 18, "年齢が18歳未満です", { age });

// カウンター
function processItem(item: string) {
  console.count("アイテム処理");
  // 処理
}

["A", "B", "C"].forEach(processItem);
// 出力:
// アイテム処理: 1
// アイテム処理: 2
// アイテム処理: 3

console.countReset("アイテム処理"); // カウンターをリセット

スタックトレース

function innerFunction() {
  console.trace("関数の呼び出し履歴");
}

function middleFunction() {
  innerFunction();
}

function outerFunction() {
  middleFunction();
}

outerFunction();
// スタックトレースが出力される

スタイリングとフォーマット

CSS スタイル(ブラウザ環境)

// %c を使用したスタイリング
console.log(
  "%c成功!%c 処理が完了しました",
  "color: green; font-weight: bold; font-size: 16px;",
  "color: black; font-weight: normal;"
);

// 複数のスタイル
console.log(
  "%cエラー %c重大な問題が発生しました",
  "background-color: red; color: white; padding: 2px 4px; border-radius: 2px;",
  "color: red;"
);

フォーマット指定子

// %s - 文字列
console.log("こんにちは、%sさん", "田中");

// %d, %i - 整数
console.log("合計: %d個", 42);

// %f - 浮動小数点
console.log("平均値: %.2f", 3.14159);

// %o - オブジェクト(展開可能)
console.log("ユーザーオブジェクト: %o", { id: 1, name: "田中" });

// %O - オブジェクト(展開不可)
console.log("ユーザーオブジェクト: %O", { id: 1, name: "田中" });

TypeScript固有の実装

型安全なラッパー

// 型安全なログレベル
enum LogLevel {
  DEBUG = 0,
  INFO = 1,
  WARN = 2,
  ERROR = 3
}

class Logger {
  constructor(private minLevel: LogLevel = LogLevel.INFO) {}

  private shouldLog(level: LogLevel): boolean {
    return level >= this.minLevel;
  }

  debug(...args: any[]): void {
    if (this.shouldLog(LogLevel.DEBUG)) {
      console.debug("[DEBUG]", ...args);
    }
  }

  info(...args: any[]): void {
    if (this.shouldLog(LogLevel.INFO)) {
      console.info("[INFO]", ...args);
    }
  }

  warn(...args: any[]): void {
    if (this.shouldLog(LogLevel.WARN)) {
      console.warn("[WARN]", ...args);
    }
  }

  error(...args: any[]): void {
    if (this.shouldLog(LogLevel.ERROR)) {
      console.error("[ERROR]", ...args);
    }
  }

  table(data: any, columns?: string[]): void {
    if (this.shouldLog(LogLevel.DEBUG)) {
      console.table(data, columns);
    }
  }
}

// 使用例
const logger = new Logger(LogLevel.INFO);
logger.debug("これは表示されない"); // minLevelがINFOのため
logger.info("これは表示される");

構造化ログ

interface LogEntry {
  timestamp: Date;
  level: string;
  message: string;
  context?: Record<string, any>;
}

class StructuredLogger {
  private format(entry: LogEntry): string {
    return JSON.stringify({
      ...entry,
      timestamp: entry.timestamp.toISOString()
    });
  }

  log(level: string, message: string, context?: Record<string, any>): void {
    const entry: LogEntry = {
      timestamp: new Date(),
      level,
      message,
      context
    };

    switch (level) {
      case "error":
        console.error(this.format(entry));
        break;
      case "warn":
        console.warn(this.format(entry));
        break;
      default:
        console.log(this.format(entry));
    }
  }

  error(message: string, error?: Error, context?: Record<string, any>): void {
    this.log("error", message, {
      ...context,
      error: error ? {
        name: error.name,
        message: error.message,
        stack: error.stack
      } : undefined
    });
  }
}

環境別の設定

開発/本番環境の切り替え

const isDevelopment = process.env.NODE_ENV === "development";

// 条件付きログ
if (isDevelopment) {
  console.log("開発環境のデバッグ情報");
}

// console メソッドの無効化(本番環境)
if (!isDevelopment) {
  console.log = () => {};
  console.debug = () => {};
  // エラーとワーニングは残す
}

// より洗練されたアプローチ
class ConditionalLogger {
  private isDev = process.env.NODE_ENV === "development";

  log(...args: any[]): void {
    if (this.isDev) {
      console.log(...args);
    }
  }

  // 本番環境でも記録したい重要な情報
  important(...args: any[]): void {
    console.log("[IMPORTANT]", ...args);
  }
}

ベストプラクティス

1. 適切なログレベルの使用

// 良い例
console.error("データベース接続エラー:", error);
console.warn("APIレート制限に近づいています");
console.info("サーバーが起動しました");
console.debug("リクエスト詳細:", requestData);

// 悪い例
console.log("エラー!!!"); // エラーにはconsole.errorを使用すべき

2. 意味のあるメッセージ

// 良い例
console.log(`ユーザー ${userId} のログイン処理完了(処理時間: ${duration}ms)`);

// 悪い例
console.log("done"); // 何が完了したか不明
console.log(data); // コンテキストがない

3. 構造化されたコンテキスト

// 良い例
console.log("注文処理エラー", {
  orderId: order.id,
  userId: user.id,
  error: error.message,
  timestamp: new Date().toISOString()
});

// 悪い例
console.log("エラー: " + order.id + " - " + user.id);

4. パフォーマンスへの配慮

// 本番環境での過度なログを避ける
class PerformantLogger {
  private cache = new Map<string, any>();
  
  logWithThrottle(key: string, message: string, delay: number = 1000): void {
    const now = Date.now();
    const lastLogged = this.cache.get(key);
    
    if (!lastLogged || now - lastLogged > delay) {
      console.log(message);
      this.cache.set(key, now);
    }
  }
}

5. セキュリティへの配慮

// センシティブな情報をマスク
function logUserData(user: any): void {
  const safeUser = {
    ...user,
    password: "[REDACTED]",
    creditCard: user.creditCard ? `****${user.creditCard.slice(-4)}` : undefined
  };
  
  console.log("ユーザーデータ:", safeUser);
}

まとめ

consoleオブジェクトは、TypeScript/JavaScript開発において最も基本的で重要なデバッグツールです。シンプルなconsole.logから、テーブル表示、グループ化、パフォーマンス測定まで、多様な機能を提供します。開発環境では積極的に活用し、本番環境では適切なログレベルとパフォーマンスを考慮した実装が重要です。より高度なロギング要件がある場合は、専用のロギングライブラリの使用を検討してください。