どっちを使うべき?TypeScriptのtype(型エイリアス)とinterfaceの違いと使い分け
この記事では、type(型エイリアス)と interface の違いと、それぞれの使い方、そしてどっちを使うべき?について解説いたします。
機能対応表
type(型エイリアス)と interface がサポートする機能の可否を一覧にしています。
| # | 機能 | type | interface | 説明 |
|---|---|---|---|---|
| 1 | 宣言のマージ | 不可 | 可能 | 同名宣言を重ねると自動で統合されるかどうか |
| 2 | 拡張(extends / &) | 制約あり(& で合成) | 可能 | 派生型を作成する手段の違い |
| 3 | プリミティブ型エイリアス | 可能 | 不可 | type ID = string のように別名を付けられるか |
| 4 | ユニオン型 | 可能 | 不可 | A | B を直接定義できるか |
| 5 | タプル型 | 可能 | 制約あり | [number, string] を自然に書けるか |
| 6 | 関数型 | 可能 | 可能 | (arg: T) => U の形を宣言できるか |
| 7 | オブジェクト型 | 可能 | 可能 | プロパティを持つ構造体を定義できるか |
| 8 | リテラル型 | 可能 | 不可 | 文字列/数値リテラルを直接型にできるか |
| 9 | 条件型 | 可能 | 不可 | A extends B ? X : Y を書けるか |
| 10 | 型アサーション | 可能 | 不可 | as const など型計算を伴うアサーションに使えるか |
| 11 | infer キーワード | 可能 | 不可 | 条件型で部分型を抽出できるか |
| 12 | typeof 演算子 | 可能 | 不可 | 実値から型を取得できるか |
| 13 | keyof 演算子 | 可能 | 不可 | プロパティ名を列挙したユニオンを生成できるか |
| 14 | インデックスシグネチャ | 可能 | 可能 | [K: string]: V を宣言できるか |
| 15 | マッピング型 | 可能 | 不可 | [K in Keys]: T で型を変換できるか |
| 16 | テンプレートリテラル型 | 可能 | 不可 | ${Uppercase<T>}Id のような型計算が可能か |
| 17 | 再帰型 | 可能 | 可能 | 自分自身を参照する型を定義できるか |
| 18 | クラスによる implements | 不可 | 可能 | class Foo implements Bar で利用できるか |
| 19 | 名前空間とのマージ | 不可 | 可能 | namespace と同名で拡張できるか |
| 20 | コールシグネチャのオーバーロード | 可能 | 制約あり | 同一型で複数の関数シグネチャを持てるか |
基本形の定義
1. 宣言のマージ(Declaration Merging)
解説
同じ名前の interface を複数回書くと自動で結合されます。type で同じことを行うと重複エラーになります。
ts// interface はマージされる
interface ApiContext { reqId: string }
interface ApiContext { user?: { id: number } }
const ctx: ApiContext = { reqId: 'abc', user: { id: 1 } };
// type はエラー
// type ApiContext = { reqId: string }
// type ApiContext = { user?: { id: number } } // ✅ 上と同名なので NG
2. 拡張(extends / &)
解説
interface は extends、type は交差型 & で派生を作成します。
tsinterface Animal { name: string }
interface Dog extends Animal { bark(): void }
type Position = { x: number }
type Position3D = Position & { z: number }
3. プリミティブ型エイリアス
解説
ID などのドメイン概念を表すときは type が便利です。interface では書けません。
tstype UserId = string | number;
const id: UserId = 42;
4. ユニオン型
解説
type でしかユニオンを直接宣言できません。interface は要素側としてのみ利用します。
tstype Status = 'draft' | 'published' | 'archived';
interface Draft { status: 'draft' }
interface Published { status: 'published' }
type ArticleState = Draft | Published;
5. タプル型
解説
type なら [number, string] を自然に定義できます。interface で表す場合は添字シグネチャが必要です。
ts// 推奨
type Pair = [number, string];
// interface で無理やり書く例
interface PairLike {
0: number;
1: string;
length: 2;
}
6. オブジェクト型
解説
どちらもサポートされますが、マージ前提なら interface、型演算前提なら type が向きます。
tsinterface User {
id: number;
name: string;
}
type ReadonlyUser = Readonly<User>;
7. 関数型
解説
シグネチャだけなら type が短く、オーバーロードを多用する場合は interface が読みやすいです。
ts// type
type ToString = (value: unknown) => string;
// interface(オーバーロード)
interface Parse {
(s: string): number;
(n: number): string;
}
8. リテラル型
解説
固定値の表現は type で行います。interface では直接書けません。
tstype Yes = 'yes';
type No = 'no';
9. 条件型
解説
ジェネリックに応じて型を切り替える強力な仕組みで、type 限定です。
tstype Nullable<T> = T extends null | undefined ? never : T;
type A = Nullable<string | null>; // string
10. 型アサーション(as const 等)
解説
type を組み合わせ、リテラルを保持したまま厳密型に変換できます。
tsconst config = {
mode: 'production',
port: 3000,
} as const;
type Config = typeof config; // { readonly mode: "production"; readonly port: 3000 }
11. infer キーワード
解説
条件型内で部分型を抽出できます。複雑な戻り値推論に便利です。
tstype ReturnTypeOf<T> = T extends (...args: any) => infer R ? R : never;
function foo() { return { ok: true } }
type R = ReturnTypeOf<typeof foo>; // { ok: boolean }
12. typeof 演算子
解説
実値から型を取得して再利用します。
tsconst defaultUser = { id: 0, name: 'guest' };
type DefaultUser = typeof defaultUser;
13. keyof 演算子
解説
オブジェクトのプロパティ名をユニオンで取り出します。
tsinterface User { id: number; name: string }
type UserKeys = keyof User; // "id" | "name"
14. インデックスシグネチャ
解説
動的キーを持つ辞書構造を表現します。
tsinterface Dictionary {
[key: string]: string;
}
type NumRecord = { [key: number]: boolean };
15. マッピング型
解説
既存キーを走査して新しい型を作成します。type 限定です。
tstype Optional<T> = { [K in keyof T]?: T[K] };
interface User { id: number; name: string }
type PartialUser = Optional<User>; // 全プロパティがオプション
16. テンプレートリテラル型
解説
文字列リテラルを組み合わせて新しい型を生成します。
tstype EventName<E extends string> = `${E}Changed`;
type Domain = 'user' | 'post';
type Events = EventName<Domain>; // "userChanged" | "postChanged"
17. 再帰型
解説
自己参照によりツリー構造を安全に記述できます。
tsinterface TreeNode<T> {
value: T;
children?: TreeNode<T>[];
}
type Json = string | number | boolean | null | Json[] | { [k: string]: Json };
18. クラスによる implements
解説
クラスが契約を満たすかコンパイル時に検証できます。interface 専用です。
tsinterface Runnable { run(): void }
class Task implements Runnable {
run() { console.log('running'); }
}
19. 名前空間とのマージ
解説
ライブラリ拡張時に namespace と interface を同名で定義し、静的メソッドを追加できます。
tsinterface Greeter { greet(): void }
namespace Greeter {
export function create(): Greeter {
return { greet() { console.log('hi'); } };
}
}
const g = Greeter.create();
g.greet();
20. コールシグネチャのオーバーロード
解説
複数シグネチャを一つの型で表現します。type なら簡潔、interface はプロパティと混在できますが書き方がやや冗長です。
ts// type 版
type Overloaded =
| ((n: number) => string)
| ((s: string) => number);
// interface 版(制約あり)
interface Fn {
(n: number): string;
(s: string): number;
}
const f: Fn = (arg: any) =>
typeof arg === 'number' ? String(arg) : arg.length;
どっちを使うべき?
結論を先に述べます。拡張性・互換性を重視するなら interface、型演算と柔軟な構成力を求めるなら type が最適です。以下ではメリット/デメリットを整理し、代表的な利用パターンごとにおすすめの選択肢を示します。
メリット/デメリット一覧
| # | 観点 | type の特徴 | interface の特徴 |
|---|---|---|---|
| 1 | 拡張性 | 宣言のマージ不可。合成は交差型 & で明示 | 宣言のマージと extends で段階的に拡張しやすい |
| 2 | 表現力 | ユニオン・条件型・テンプレートリテラル型など高度な型演算が可能 | 構造宣言に特化。リテラル・条件型など直接記述は不可 |
| 3 | IDE 補完 | 型計算が多いと補完候補が長くなる傾向 | オブジェクト構造を宣言するため補完が直感的 |
| 4 | ライブラリ互換 | 外部公開では breaking change を誘発しやすい | 再宣言マージで後方互換を保ちやすい |
| 5 | 学習コスト | 条件型や infer を理解する必要がある | Java Interface に近く初学者に理解しやすい |
パターン別おすすめ
| # | シーン | 推奨 | 理由 |
|---|---|---|---|
| 1 | 公開 SDK・型定義ファイル | interface | ユーザー側で拡張できるため将来互換が保たれる |
| 2 | 内部ユーティリティ関数群 | type | 条件型・テンプレートリテラル型で汎用型を生成しやすい |
| 3 | REST API レスポンス DTO | interface | バージョンごとの追加項目を宣言マージで吸収できる |
| 4 | Redux Action など列挙的ユニオン | type | 複数リテラルを ` |
| 5 | ドメイン ID や定数の別名 | type | プリミティブ別名を簡潔に定義できる |
| 6 | プラグインアーキテクチャ | interface + type | 外部契約を interface、オプション型を type で表現 |
| 7 | JSX Props 型(拡張前提) | interface | extends で派生コンポーネントに対応しやすい |
| 8 | 再帰ツリーや JSON 型 | type | 再帰型と条件型を組み合わせた表現が容易 |
運用のヒント
- ライブラリや共有コードでは「まず
interfaceで契約を定義し、必要に応じてtypeで派生型を組み立てる」方針が安全です。- アプリ内部ロジックでは
typeを主役にし、ユニオン・条件型で型安全と可読性を高めると保守が楽になります。- 型選択はファイル単位で統一せず、機能ごとに最適な方を柔軟に混在させると設計が洗練されます。
まとめ
最初に押さえるべき核心は 「拡張性なら interface、型演算なら type」 というシンプルな方針です。
宣言のマージや extends による段階的拡張が必要な公開 API では interface が安全であり、ユニオン・条件型・テンプレートリテラル型など高度な表現力を活かしたい内部ユーティリティでは type が威力を発揮します。
実装面では次の三点を意識すると設計が安定します。
-
契約を先に定義し拡張は後から加える
外部向けの DTO やプラグイン API はinterfaceで宣言し、互換性を維持したまま追加できる形にする。 -
型演算は専用のユーティリティ型に集約する
typeの条件型やinferを使い回し、実ロジック側をシンプルに保つことで可読性を高める。 -
IDE 補完とコンパイルエラーの質を常に評価する
interfaceの直感的な補完とtypeの強力な型ガードを使い分け、開発者体験を最適化する。
最後に、チームルールを「宣言マージ=interface」「型演算=type」と明確に分けるだけでも保守コストは大幅に削減されます。
ぜひ活用してみてください。
関連リンク
articleTypeScript Null 安全戦略の比較検証:ts-reset vs strictNullChecks vs noUncheckedIndexedAccess
articleESM/CJS 地獄から脱出!「ERR_REQUIRE_ESM」「import 文が使えない」を TypeScript で直す
articleTypeScript 型安全なフィーチャーフラグ設計:判別可能共用体で運用事故を防ぐ
articleTypeScript satisfies 演算子の実力:型の過剰/不足を一発検知する実践ガイド
articlePlaywright × TypeScript 超入門チュートリアル:型安全 E2E を最短構築
articleTypeScript 型カバレッジを KPI 化:`type-coverage`でチームの型品質を可視化する
articleYarn vs npm vs pnpm 徹底比較:速度・メモリ・ディスク・再現性を実測
articleWeb Components と Declarative Shadow DOM の現在地:HTML だけで描くサーバー発 UI
articleVue.js ルーター戦略比較:ネスト/動的セグメント/ガードの設計コスト
articleCursor × Monorepo 構築:Yarn Workspaces/Turborepo/tsconfig path のベストプラクティス
articleTailwind CSS のコンテナクエリ vs 伝統的ブレイクポイント:適応精度を実測
articleCline × Monorepo(Yarn Workspaces)導入:パス解決とルート権限の最適解
blogiPhone 17シリーズの発表!全モデルiPhone 16から進化したポイントを見やすく整理
blogGoogleストアから訂正案内!Pixel 10ポイント有効期限「1年」表示は誤りだった
blog【2025年8月】Googleストア「ストアポイント」は1年表記はミス?2年ルールとの整合性を検証
blogGoogleストアの注文キャンセルはなぜ起きる?Pixel 10購入前に知るべき注意点
blogPixcel 10シリーズの発表!全モデル Pixcel 9 から進化したポイントを見やすく整理
blogフロントエンドエンジニアの成長戦略:コーチングで最速スキルアップする方法
review今の自分に満足していますか?『持たざる者の逆襲 まだ何者でもない君へ』溝口勇児
reviewついに語られた業界の裏側!『フジテレビの正体』堀江貴文が描くテレビ局の本当の姿
review愛する勇気を持てば人生が変わる!『幸せになる勇気』岸見一郎・古賀史健のアドラー実践編で真の幸福を手に入れる
review週末を変えれば年収も変わる!『世界の一流は「休日」に何をしているのか』越川慎司の一流週末メソッド
review新しい自分に会いに行こう!『自分の変え方』村岡大樹の認知科学コーチングで人生リセット
review科学革命から AI 時代へ!『サピエンス全史 下巻』ユヴァル・ノア・ハラリが予見する人類の未来