tanaka101

インターフェースと型エイリアス

オブジェクトの型に名前をつける方法を学ぼう

なぜ型に名前をつけるのか

前のセクションで、オブジェクトに直接型を書く方法を学びました。

let user: { name: string; age: number; email: string } = {
  name: "田中",
  age: 25,
  email: "tanaka@example.com",
};

これでも動きますが、同じ型を複数の場所で使う場合に問題が出ます。

// 同じ型を何度も書くのは大変...
function greet(user: { name: string; age: number; email: string }): string {
  return `こんにちは、${user.name}さん`;
}
 
function sendEmail(user: { name: string; age: number; email: string }): void {
  console.log(`${user.email} にメールを送信`);
}

型に名前をつければ、1回の定義で使い回せます。
には名前をつける方法が2つあります。interfacetype です。

interface(インターフェース)

interface はオブジェクトの型に名前をつける仕組みです。

interface User {
  name: string;
  age: number;
  email: string;
}

定義した User を型として使えます。

const user: User = {
  name: "田中",
  age: 25,
  email: "tanaka@example.com",
};
 
function greet(user: User): string {
  return `こんにちは、${user.name}さん`;
}
 
function sendEmail(user: User): void {
  console.log(`${user.email} にメールを送信`);
}

型定義が1か所にまとまり、すっきりしました。

省略可能なプロパティ

プロパティ名の後ろに ? をつけると、そのプロパティは省略可能になります。

interface User {
  name: string;
  age: number;
  email: string;
  nickname?: string;  // 省略可能
}
 
// nickname がなくてもOK
const user1: User = { name: "田中", age: 25, email: "tanaka@example.com" };
 
// nickname があってもOK
const user2: User = { name: "佐藤", age: 30, email: "sato@example.com", nickname: "さとちゃん" };

readonly(読み取り専用)

readonly をつけると、一度設定した値を変更できなくなります。

interface User {
  readonly id: string;
  name: string;
  age: number;
}
 
const user: User = { id: "001", name: "田中", age: 25 };
 
user.name = "佐藤";  // OK: name は変更できる
user.id = "002";     // エラー: id は readonly なので変更できない

ID のように「一度決めたら変わらない値」に使います。

type(型エイリアス)

type も型に名前をつける仕組みです。

type User = {
  name: string;
  age: number;
  email: string;
};

使い方は interface とほとんど同じです。

const user: User = {
  name: "田中",
  age: 25,
  email: "tanaka@example.com",
};

type はオブジェクト以外にも使える

interface は主にオブジェクトの型に使いますが、type はどんな型にも名前をつけられます。

// プリミティブ型に名前をつける
type UserId = string;
type Age = number;
 
// 関数の型に名前をつける(前のセクションで登場)
type CalcFunction = (x: number, y: number) => number;
 
// リテラル型(特定の値だけ許可する)
type Status = "active" | "inactive" | "suspended";

interface ではこれらの定義はできません。

interface と type の違い

interfacetype
オブジェクトの型定義できるできる
の定義できないできる
型の定義できる(書き方が異なる)できる
Union型(後述)できないできる
extends(拡張)できる& で交差型を使う
同名で宣言した場合マージされるエラー

extends(拡張)

既存の型を元にプロパティを追加した新しい型を作れます。

// interface の場合: extends を使う
interface User {
  name: string;
  age: number;
}
 
interface Employee extends User {
  department: string;
  employeeId: string;
}
 
// Employee は User のプロパティも全て持つ
const employee: Employee = {
  name: "田中",
  age: 25,
  department: "開発部",
  employeeId: "E001",
};
// type の場合: & (交差型)を使う
type User = {
  name: string;
  age: number;
};
 
type Employee = User & {
  department: string;
  employeeId: string;
};

どちらも結果は同じです。

どちらを使うべきか

これもチームや現場によって方針が異なりますが、よくある使い分けを紹介します。

用途よく使われるもの理由
オブジェクトの型定義interface拡張(extends)が直感的で読みやすい
Union型やリテラル型typeinterface では定義できない
の型type書き方がシンプル
に別名をつけるtypeinterface では定義できない

迷ったら interface を使い、interface で書けない場合に type を使う

これが最もシンプルな判断基準です。
ただし、プロジェクトやチームによっては「全て type で統一する」方針のところもあります。
チームのルールがあればそれに従いましょう。

実践的な例

勤怠管理のデータを型で定義してみましょう。

// 勤怠記録の型
interface AttendanceRecord {
  readonly id: string;
  employeeName: string;
  date: string;
  clockIn: string;
  clockOut: string | null;  // 退勤前は null
  note?: string;            // 備考(任意)
}
 
// ステータスの型(特定の値のみ許可)
type AttendanceStatus = "出勤中" | "退勤済み" | "欠勤";
 
// 使用例
const record: AttendanceRecord = {
  id: "R001",
  employeeName: "田中",
  date: "2026-01-28",
  clockIn: "09:00",
  clockOut: null,
  note: "在宅勤務",
};
 
const status: AttendanceStatus = "出勤中";

interface でオブジェクトの構造を定義し、type で特定の値のみ許可する型を定義しています。
この使い分けが実務でも一般的なパターンです。

セクションまとめ

  • interface と type で型に名前をつけられる
  • ? で省略可能なプロパティ、readonly で変更不可のプロパティを定義できる
  • interface はオブジェクト向け、type はどんな型にも使える
  • 迷ったら interface を使い、interface で書けない場合に type を使う