TypeScriptでよく使われるtype
とinterface
。どちらも型を定義するために使用しますが、それぞれ異なる特徴や使い方があります。「type
とinterface
、どっちを使えばいいの?」という疑問にお答えするため、このブログでは以下のポイントを初心者にも分かりやすく解説します。
- それぞれの基本的な使い方
- 違いと特徴
- 実際にどう使い分けるべきか
型の定義
interface
interface
はオブジェクトの構造を定義するのに便利な機能です。特にオブジェクト型に対して多くの機能が用意されています。
interface User {
name: string;
age: number;
}
const user: User = {
name: "Taro",
age: 25,
};
interface
の特徴
- オブジェクト型専用の機能。
- 再利用性が高く、
extends
による拡張が可能。 - 型のマージができる(後述)。
type
type
は型エイリアスを作成するための機能です。interface
よりも幅広い型を定義できます。
type User = {
name: string;
age: number;
};
type ID = string | number;
const userId: ID = "abc123"; // 文字列または数値を許容
type
の特徴
- オブジェクト型以外の型(プリミティブ型、ユニオン型、タプル型など)も定義可能。
- 柔軟性が高く、複雑な型操作に向いている。
interface
とtype
の違い
両者は似ていますが、いくつかの重要な違いがあります。
宣言と代入
interface
は型の「宣言」として扱われるため、同じ名前のinterface
を複数回宣言するとマージ(結合)されます。一方、type
は型の「代入」として扱われるため、同じ名前で再定義することはできません。
// interfaceのマージ
interface Example {
prop: string;
}
interface Example {
anotherProp: number;
}
const example: Example = {
prop: "hello",
anotherProp: 123,
};
// typeの再定義はエラー
type ExampleType = { prop: string };
// type ExampleType = { anotherProp: number }; // エラー
定義できる型の種類
interface
はオブジェクト型の定義に特化していますが、type
はより柔軟で、ユニオン型、タプル型やプリミティブ型など、幅広い型を定義できます。
// typeで定義可能なユニオン型
type ID = string | number;
// typeでタプル型を定義
type Coordinates = [number, number];
type Color = "red" | "blue" | "green";
拡張
interface
はextends
を使って継承できます。一方、type
は&
を使って型を合成します。
// interfaceで拡張
interface Person {
name: string;
}
interface Employee extends Person {
employeeId: number;
}
const employee: Employee = {
name: "Taro",
employeeId: 123,
};
// typeで型を合成
type PersonType = { name: string };
type EmployeeType = PersonType & { employeeId: number };
const employeeType: EmployeeType = {
name: "Taro",
employeeId: 123,
};
再定義・型のマージに関する注意点
- 再定義:
interface
は同名の型を複数回宣言可能(型がマージされる)が、type
では同名の型を再定義するとエラーとなる。
// interfaceでのマージ例
interface Example {
a: number;
}
interface Example {
b: string;
}
const obj: Example = { a: 1, b: "text" }; // 有効
// typeでのエラー例
type Example = { a: number };
type Example = { b: string }; // エラー: 'Example' が重複しています
補足例
- 型の柔軟性を示すコード例
// typeでユニオン型やタプル型の定義例
type ApiResponse = { success: boolean } | { error: string };
type Coordinates = [number, number];
- 拡張方法の比較
// interfaceの拡張
interface Person {
name: string;
}
interface Employee extends Person {
employeeId: number;
}
// typeの型合成
type PersonType = { name: string };
type EmployeeType = PersonType & { employeeId: number };
どちらを使う?
type
とinterface
のどちらを使うべきかは、用途やチームのコーディングスタイルによって異なります。それぞれの特徴を理解して適切に使い分けましょう。
interface
派
- 理由:
- オブジェクト指向の設計に馴染む。
- 型の拡張性が高い。
- TypeScriptライブラリやフレームワークでよく使用される。
- 使用例
interface ComponentProps { title: string; description?: string; // オプショナルプロパティ }
type
派
- 理由:
- 汎用性が高い。
- ユニオン型やタプル型を多用する場合に便利。
type
で一貫した書き方を好む場合。
- 使用例
type ApiResponse = { data: any } | { error: string };
まとめ
TypeScriptのtype
とinterface
はどちらも型を定義するために使われますが、それぞれの特徴や用途には明確な違いがあります。
interface
:- オブジェクト型に特化しており、型の拡張や再利用性が高い。
- TypeScriptが推奨する標準的な型定義方法として多くの場面で使用される。
type
:- オブジェクト型以外にもユニオン型やタプル型を定義できる汎用性がある。
- 柔軟性が高く、複雑な型を操作する際に便利。
使い分けの指針:
- オブジェクト型を中心とした構造には
interface
を使う。 - プリミティブ型やユニオン型、タプル型などの柔軟性が必要な場面では
type
を選ぶ。
最終的には、プロジェクトのコーディングスタイルやチームの好みに応じて一貫性を持たせることが重要です。このブログを参考に、自分の開発に最適な方法を選んでみてください!