TypeScript の型定義: Interface と Class の比較
TypeScript では、Interface と Class はどちらもオブジェクトの構造を定義するために使用されますが、その目的と使用方法には違いがあります。
Interface
- 使い方
- 型チェック
変数や関数の引数、戻り値の型を厳密に定義する。 - オブジェクトの形状を定義
共通の構造を持つオブジェクトを定義する。
- 型チェック
- 特徴
- 実装の詳細を定義しない。
- 複数のインターフェースを継承できる。
- クラスや他のインターフェースに実装される。
- 目的
オブジェクトの形状や構造を定義する契約のようなものです。
例
interface Person {
name: string;
age: number;
}
function greet(person: Person) {
console.log("Hello, " + person.name + "!");
}
Class
- 使い方
- オブジェクトの生成
新しいオブジェクトを作成する。 - オブジェクト指向プログラミング
クラスベースの設計パターンを実装する。
- オブジェクトの生成
- 特徴
- プロパティとメソッドを持つことができる。
- インスタンス化してオブジェクトを作成できる。
- 継承を使ってクラスを拡張できる。
- 目的
オブジェクトの構造と振る舞いを定義するブループリントです。
class Person {
name: string;
age: number;
constructor(name: string, age: number) {
this.name = name;
this.age = age;
}
greet() {
console.log("Hello, " + this.name + "!");
}
}
使い分けのポイント
- 複数のクラスで共通の形状を定義
インターフェースを定義して、クラスに実装させる。 - オブジェクトの生成と振る舞い
クラスが適している。 - 単なる形状の定義
インターフェースが適している。
function greet(person: Person) { console.log("Hello, " + person.name + "!"); }
// インターフェースを使ってオブジェクトを定義 const person1: Person = { name: "Alice", age: 30 };
greet(person1); // Output: Hello, Alice! ``
このコードで何が起こっているか
- Interface Person
name
という文字列とage
という数値を持つオブジェクトの構造を定義しています。 - greet 関数
Person
インターフェース型のperson
パラメータを受け取ります。関数内では、person.name
とperson.age
にアクセスすることで、その情報を使用できます。 - person1 オブジェクト
Person
インターフェースに準拠したオブジェクトを定義しています。 - 関数呼び出し
greet
関数にperson1
オブジェクトを渡すと、person.name
の値である "Alice" が出力されます。
-
特徴
- プロパティとメソッドを持つことができる。 -`typescript class Person { name: string; age: number;
constructor(name: string, age: number) { this.name = name; this.age = age; }
greet() { console.log("Hello, " + this.name + "!"); } }
// クラスのインスタンスを作成 const person2 = new Person("Bob", 25); person2.greet(); // Output: Hello, Bob!
**このコードで何が起こっているか:**
1. **`Person` Class:** `name` と `age` というプロパティを持つクラスを定義しています。コンストラクタを使用して、オブジェクトが作成されるときにこれらのプロパティを初期化します。
2. **`greet` メソッド:** `Person` クラスのインスタンスが持つメソッドです。`this.name` を使用して、そのインスタンスの `name` プロパティにアクセスします。
3. **インスタンス作成:** `new` キーワードを使用して、`Person` クラスの新しいインスタンスを作成します。
4. **メソッド呼び出し:** `person2` インスタンスの `greet` メソッドを呼び出し、"Hello, Bob!" が出力されます。
**TypeScript の型定義: Interface と Class の比較**
**Interface と Type の違い:**
- **Interface:** オブジェクトとクラスの型のみ定義できます。
- **Type:** 他の型も参照できます。
**Interface と Class の違い:**
- **Interface:** 実装の詳細を定義しない。
- **Class:** プロパティとメソッドを持つことができる。
**Interface と Type の比較 (詳細):**
- **継承:** Interface は継承できますが、Type はできません。
- **同名要素の宣言:** Interface では同じ名前のプロパティを複数宣言できますが、Type ではエラーになります。
- **Class への実装:** Interface はクラスに実装できますが、Type はできません。
- **交差型、共用体型、タプル型:** Interface と Type の両方で使用できます。
- **Mapped Types:** Interface と Type の両方で使用できます。
- **規定しないプロパティの扱い:** Interface では規定しないプロパティを追加できますが、Type ではエラーになります。
これらの比較を理解することで、TypeScript で適切な型定義を選択できるようになります。
TypeScript では、Interface と Class を適切に使い分けることで、コードの型安全性と再利用性を向上させることができます。しかし、特定の状況では、これらのアプローチの代替案を考えることもできます。
Type Alias
Type Alias は、既存の型に新しい名前を付けるための仕組みです。Interface と似ていますが、より柔軟な使い方があります。
type Person = {
name: string;
age: number;
};
Generic Types
Generic Types は、型パラメータを使用して、再利用可能な型定義を作成する手法です。
interface GenericIdentityFn<T> {
(arg: T): T;
}
function identity<T>(arg: T): T {
return arg;
}
Utility Types
TypeScript には、便利な型定義を提供する組み込みの Utility Types があります。例えば、Partial
, Required
, Readonly
などがあります。
interface Person {
name: string;
age: number;
address?: string;
}
// Partial<Person> は、Person のプロパティをすべてオプションにする
type PartialPerson = Partial<Person>;
Interface と Class の比較において、Type Alias や Generic Types を組み合わせることで、より柔軟な型定義が可能になります。
Type Alias と Generic Types の組み合わせ
type GenericIdentityFn<T> = (arg: T) => T;
function identity<T>(arg: T): T {
return arg;
}
interface Person {
name: string;
age: number;
address?: string;
}
// Required<Person> は、Person のプロパティをすべて必須にする
type RequiredPerson = Required<Person>;
typescript class interface