TypeScriptの機能としてinterfaceがあります。
しかし、その機能が抽象classやtypeエイリアスの考え方と似ており違いがわからなかったので調べてみました。
interfaceとは?
TypeScript Deep Dive 日本語版によると、TypeScriptのinterfaceは次のように説明されています。
オブジェクトの構造を宣言するための多くの機能
実際のコードを用いて宣言の仕方を説明します。
「このオブジェクトにはname, age, greetというメンバーがありますよ〜」ということを宣言します。
// interfaceを定義
interface PersonInterface {
age: number;
name: string;
greet(phrase: string): void;
}
// オブジェクトを作成
let kengo: PersonInterface;
kengo = {
age: 21,
name: 'Kengo H',
greet(phrase: string) {
console.log('Hi there, ' + phrase);
}
};
typeと比較
このコンセプトを見ると、typeエイリアスと似ていると思いませんか?
実際に、ほぼ一行で同じ処理ができます。
type PersonType = {
age: number;
name: string;
greet(phrase: string): void;
};
let kengo: PersonType;
kengo = {
age: 21,
name: 'Kengo H',
greet(phrase: string) {
console.log('Hi there, ' + phrase);
}
};
これならtypeの方が直感的でわかりやすいと思ってしまいます。
記述できる型の種類が違う
しかし、これらの大きな違いはinterfaceではオブジェクトの型定義しかできないということです。
逆に、typeでは次のような型定義もできます。
type Combinable = number | string;
type Conversions = 'as-number' | 'as-string';
interfaceはclassに埋め込むことができる
interfaceでは、プロパティやメソッドといった機能性をまとめて定義したうえでclassに埋め込むことができます。
この特徴は抽象classの考え方と少し似ています。
特にプロパティやメソッドの存在を保証するという点です。
この例では、Greetableが埋め込まれたclass Personにnameプロパティやgreetメソッドが存在するということがすぐにわかります。
// interfaceを定義. greetするためのproperty, functionを定義.
interface Greetable {
name: string;
greet(phase: string): void;
}
// classに埋め込む.
class Person implements Greetable {
name: string;
constructor(_name: string) {
this.name = _name;
}
greet(phase: string): void {
console.log(`Hi, I am ${this.name} ` + phase);
}
}
abstract class (抽象class)と比較
この特徴は抽象classと似ていますね。
上記の2つ目の機能は、classに埋め込むことでプロパティやメソッドの存在を保証でき、便利になるというものです。
この考え方は抽象classと同じです。
// 抽象classを定義
abstract class Animal {
name: string;
constructor(_name: string) {
this.name = _name;
}
abstract greet(phrase: string): void;
}
// 継承
class Person extends Animal {
constructor(_name: string) {
super(_name);
}
greet(phrase: string): void {
console.log('hi ' + phrase);
}
}
複数のinterfaceはclassに埋め込むことができる
抽象classと違って、1つのclassにはinterfaceを複数埋め込むことができます。
class Person implements Greetable, AnotherInterface {
name: string;
}
interfaceを使うメリット
これまでtypeや抽象classとの違いを見てきましたが、これらを踏まえてinterfaceの利点についても考えていきます。
interfaceはtypeよりも多機能
interface同士で継承することができる
typeでは継承のようなことは可能ですが、継承自体はできません。
interface Named {
name: string;
}
interface Greetable extends Named, AnotherInterface {
greet(phase: string): void;
}
classに埋め込むことができる
typeではできませんが、interfaceではできます。
interface Greetable {
....
}
class Person implements Greetable {
....
}
抽象classよりも柔軟に使える
抽象classを使う方法では1つのクラスしか継承できません。
しかし、interfaceはclassに対して複数埋め込むことができます。
そのため、機能性ごとにinterfaceを宣言しておくことで柔軟に使うことが可能です。
まとめ
interfaceのコンセプトはtypeと似ていますが、typeよりも多機能です。
抽象classよりも柔軟に使うことができます。