— type & vs interface extends の速度差を可視化する —

— type & vs interface extends の速度差を可視化する —

投稿日: 2025年10月22日

学習振り返り
要約
  • TypeScriptにおけるtypeの交差型(&)とinterfaceの継承(extends)を用いた型定義のパフォーマンスを比較した。
  • interfaceベースの型定義は、typeよりも型チェック時間が約3倍速く、開発体験(DX)にも優れた影響を与える。
  • 実務においては、ReactのProps型をinterfaceで統一することが最適解とされる。
音声で記事を再生
0:00

🧠 TypeScript 型定義パフォーマンス検証

type & vs interface extends の速度差を可視化する —

🎯 概要

TypeScript の大型コードベースで、コンパイル時間が妙に長い… と感じたことはありませんか?
実はそれ、type の交差型(&)が原因かもしれません。

この記事では、React の Props を例に
typeinterface の**型チェック時間(Check time)**を比較した検証デモを紹介します。


🧩 検証の目的

TypeScript では型を合成する方法が複数ありますが、
よく使われるのが次の2つです:

// ① type + &
type A = { name: string }
type B = { age: number }
type C = A & B

// ② interface + extends
interface A { name: string }
interface B extends A { age: number }

一見同じように見えますが、内部処理が大きく異なり、
パフォーマンス(型解析時間)に数倍の差が出ます。


⚙️ 環境とツール

  • Node.js 24.x(v18 以上なら可)

  • TypeScript 5.6

  • 計測コマンド:

    • tsc --extendedDiagnostics

    • /usr/bin/time -lp(実時間・メモリ使用量の確認)


🧪 検証方法

1️⃣ 型定義を自動生成

# 400件の型ブロックを生成(デフォルト)
npx ts-node scripts/generate.ts

# 1000件に増やす
npx ts-node scripts/generate.ts 1000

# interface 版・type 版が src/ 以下に生成されます

生成スクリプトでは、
type では交差型 &
interface では継承 extends を再帰的に合成していきます。


2️⃣ 型検査時間を計測

npm run bench:type
npm run bench:iface

出力結果に表示される Check time が型解析にかかった純粋な時間です。

実行例(N=3000)

— type & vs interface extends の速度差を可視化する —|ShiftBブログ

➡️ 約3倍の速度差が出ています。
type の方が非線形に遅くなる)


3️⃣ 実時間も計測(任意)

/usr/bin/time -lp npm run bench:type
/usr/bin/time -lp npm run bench:iface

real(実行時間)や maximum resident set size(最大常駐メモリ)を比較します。


🔍 結果の分析

— type & vs interface extends の速度差を可視化する —|ShiftBブログ

💡 理由

  • type(交差型)

    • 即時評価(Eager Evaluation)

    • & のたびに再帰的に展開 → 構造爆発

    • キャッシュが効きにくい

  • interface(継承)

    • 遅延評価(Lazy Evaluation)

    • 「名前付き参照」でキャッシュが効く

    • スケールしても安定


🧠 補足:VSCodeでの体感差

  • type & の場合 → 補完やホバー時に数秒ラグが発生することも

  • interface の場合 → 遅延展開されるため即応答

実務では補完レスポンスの速さが大きく変わるため、
開発体験 (DX) の観点でも interface が圧倒的に有利です。


🧰 実務での指針

— type & vs interface extends の速度差を可視化する —|ShiftBブログ

✅ ESLint 推奨設定

{
  "rules": {
    "@typescript-eslint/consistent-type-definitions": ["error", "interface"]
  }
}

⚠️ Simplify<T> の扱いに注意

type Simplify<T> = { [K in keyof T]: T[K] }

便利ですが、大量の型を一気に展開すると逆効果です。
局所的(最終出力段階)でのみ使用しましょう。


🧩 トラブルシュート

⚙️ ts-node 警告(MODULE_TYPELESS_PACKAGE_JSON)

Warning: Module type of file is not specified...

package.json"type": "module" を追加すれば解消できます。
動作自体には影響ありません。


📊 まとめ

— type & vs interface extends の速度差を可視化する —|ShiftBブログ

🧠 結論
React などの Props 型は、
interface ベースで統一するのが最適解。

📦 GitHub リポジトリ

🧩 検証コード・スクリプト一式はこちらで公開しています:
👉 https://github.com/Kazuya-Sakashita/ts-perf-demo

# クローンして実行
git clone https://github.com/Kazuya-Sakashita/ts-perf-demo.git
cd ts-perf-demo
npm i
npx ts-node scripts/generate.ts
npm run bench:type
npm run bench:iface

シェア!

XThreads
icon
さかした
おじさんでも学べる!をモットーに。 以前はRuby(約4年)、今は React / Next.js を中心に、学習中。個人開発を中心にして、スキルアップを目指しています。
Loading...
記事一覧に戻る
XThreads
0