インターフェース
オブジェクトの形を定義する強力な機能
インターフェースとは?
日常での例え:設計図・仕様書
建築の設計図
「この建物には玄関、リビング、寝室が必要」
と構造を決める
interface
「このオブジェクトにはname, age, emailが必要」
と構造を決める
なぜinterfaceが必要?
毎回同じ型を書くのは大変:
- ユーザー情報を使う場所が10箇所あったら、10回書く?
- プロパティを追加したら、10箇所全部直す?
interfaceなら:1箇所で定義、どこでも使い回せる!
基本的な使い方
interfaceの定義
オブジェクトの形を定義
typescript
// interfaceを定義
interface User {
id: number;
name: string;
email: string;
}
// interfaceを使う
const user: User = {
id: 1,
name: "田中太郎",
email: "tanaka@example.com"
};
// 関数の引数にも使える
function greetUser(user: User) {
console.log(`こんにちは、${user.name}さん!`);
}
// 配列の型にも使える
const users: User[] = [user];プレビュー
interface User {
id: number
name: string
}
オプショナルプロパティ
あってもなくてもいいプロパティ
typescript
interface User {
id: number;
name: string;
email: string;
age?: number; // ? = オプショナル
phone?: string; // なくてもOK
}
// ageとphoneは省略可能
const user1: User = {
id: 1,
name: "田中",
email: "tanaka@example.com"
};
// あってもOK
const user2: User = {
id: 2,
name: "鈴木",
email: "suzuki@example.com",
age: 30
};プレビュー
age?: number
// ? をつけると省略可能に
読み取り専用プロパティ
変更を禁止する
typescript
interface Config {
readonly apiKey: string;
readonly baseUrl: string;
timeout: number;
}
const config: Config = {
apiKey: "abc123",
baseUrl: "https://api.example.com",
timeout: 5000
};
// readonlyは変更できない
config.apiKey = "xyz"; // ❌ エラー!
// readonlyじゃないプロパティは変更OK
config.timeout = 10000; // ✅ OKプレビュー
readonly apiKey: string
// 一度設定したら変更禁止
関数を含むinterface
メソッドの定義
関数もプロパティとして定義
typescript
interface Calculator {
// 書き方1: メソッド記法
add(a: number, b: number): number;
// 書き方2: プロパティ記法
subtract: (a: number, b: number) => number;
}
const calc: Calculator = {
add(a, b) {
return a + b;
},
subtract: (a, b) => a - b
};
console.log(calc.add(5, 3)); // 8
console.log(calc.subtract(5, 3)); // 2プレビュー
// メソッドも型定義できる
add(a, b): number
subtract: (a, b) => number
interfaceの拡張(extends)
日常での例え:基本プランとオプション追加
「基本プラン」に「プレミアムオプション」を追加して「プレミアムプラン」に
extendsは既存のinterfaceに機能を追加します
extendsで拡張
既存のinterfaceを継承
typescript
// 基本のinterface
interface Animal {
name: string;
age: number;
}
// Animalを拡張してDogを作る
interface Dog extends Animal {
breed: string; // 犬種を追加
bark(): void; // メソッドも追加
}
const dog: Dog = {
name: "ポチ",
age: 3,
breed: "柴犬",
bark() {
console.log("ワンワン!");
}
};
// Dogはname, age, breed, barkすべて必要プレビュー
interface Dog extends Animal
// AnimalのプロパティをすべてDogを含む
複数のinterfaceを拡張
複数を組み合わせる
typescript
interface Named {
name: string;
}
interface Aged {
age: number;
}
interface Emailable {
email: string;
}
// 複数を同時に拡張
interface User extends Named, Aged, Emailable {
id: number;
}
const user: User = {
id: 1,
name: "田中",
age: 25,
email: "tanaka@example.com"
};プレビュー
extends A, B, C
// 複数のinterfaceを組み合わせ
interface vs type
どっちを使う?
基本的にはどちらでもOK!ほぼ同じことができます。
チームで統一するか、以下の使い分けを参考に:
interface が向いている
- オブジェクトの形を定義
- クラスで実装(implements)
- 拡張(extends)を多用する
- 宣言マージが必要
type が向いている
- Union型(A | B)
- プリミティブ型のエイリアス
- タプル型
- 複雑な型の演算
同じことができる例
どちらでも書ける
typescript
// interface
interface User1 {
name: string;
age: number;
}
// type
type User2 = {
name: string;
age: number;
};
// どちらも同じように使える
const user1: User1 = { name: "田中", age: 25 };
const user2: User2 = { name: "鈴木", age: 30 };プレビュー
// オブジェクトの型定義なら
// interfaceでもtypeでもOK
typeでしかできないこと
Union型やプリミティブ型
typescript
// Union型はtypeで
type Status = "pending" | "approved" | "rejected";
// プリミティブのエイリアスはtypeで
type ID = string | number;
// タプルはtypeで
type Point = [number, number];
// これらはinterfaceでは書けないプレビュー
type Status = "A" | "B"
// Union型はtypeを使う
interfaceでしかできないこと
宣言マージ
typescript
// 宣言マージ: 同名のinterfaceが合体する
interface Window {
myCustomProperty: string;
}
// 既存のWindow型に追加される
// ライブラリの型を拡張する時に便利
// typeは同名で再定義するとエラー
type MyType = { a: string };
type MyType = { b: number }; // ❌ エラー!プレビュー
// interfaceは同名で追加できる
// (宣言マージ)
実践的な使い方
APIレスポンスの型
実際のプロジェクトでよく使う
typescript
// APIレスポンスの型定義
interface ApiResponse<T> {
data: T;
status: number;
message: string;
}
interface User {
id: number;
name: string;
email: string;
}
// 使用例
async function fetchUser(id: number): Promise<ApiResponse<User>> {
const response = await fetch(`/api/users/${id}`);
return response.json();
}
// 型安全にアクセス
const result = await fetchUser(1);
console.log(result.data.name); // 補完が効く!プレビュー
// APIの型を定義すると
// レスポンスの型が保証される
Reactコンポーネントのprops
フロントエンド開発で頻出
typescript
// Reactコンポーネントのprops型
interface ButtonProps {
label: string;
onClick: () => void;
variant?: "primary" | "secondary";
disabled?: boolean;
}
function Button({ label, onClick, variant = "primary", disabled }: ButtonProps) {
return (
<button
onClick={onClick}
disabled={disabled}
className={variant}
>
{label}
</button>
);
}
// 使用時に型チェック
<Button label="送信" onClick={() => {}} /> // ✅
<Button label={123} onClick={() => {}} /> // ❌ エラープレビュー
// propsの型を定義すると
// コンポーネントが安全に使える