皆さんは、TypeScriptでインターフェースを活用していますか?
オブジェクト指向型の言語では特に重要視される機能ですが、使い方がよく分からないといった方も中にはいるかと思います。
そこで今回は、TypeScriptでインターフェースを定義する方法や使い方について、詳しく解説していきたいと思います。
TypeScriptのインターフェースとは?
JavaScriptには、インターフェースに相当する構文は残念ながら用意されていませんが、TypeScriptでは 「interface」 のキーワードで定義することができます。
インターフェースとは、特定のオブジェクトが持つべきプロパティやメソッドを定義した型のことを言います。
オブジェクトの構造を定義することにより、コードの安全性や予測可能性を高めることができる便利な機能となっています。
インターフェースの主な役割は、実際にそのプロパティやメソッドがどのような処理をするか、或いは使用されるかといった中身を定義することではなく、そのオブジェクトを使用する上で必要な要件 (構造) が何であるかを示すことにあります。
そのため、インターフェースで定義するのはプロパティ名やその型、または関数名と引数や戻り値の有無などだけであり、プロパティの値や関数の処理内容などは記述しません。
また、定義したインターフェースを実装したオブジェクトは、そのインターフェースが求める構造に従ってプロパティやメソッドを保持する必要があります。
これにより、そのオブジェクトに必要な処理が正しく実装されているかどうかをチェックすることができます。
interfaceの使い方
インターフェースの定義方法や、具体的な使用方法について、順に解説していきます。
基本構文
まずは、基本構文から見ていきましょう。
インターフェースを定義する際は、以下のような構文で記述します。
【基本構文】
interface インターフェース名 {
プロパティ名1: 型;
プロパティ名2: 型;
...
}
例えば次のように、 「Student」 インターフェースを定義した場合、そのインターフェースを実装したオブジェクトでは、 string型のプロパティ 「name」 と、number型のプロパティ 「age」 を必ず所持する必要があります。
【サンプルコード】
interface Student {
name: string;
age: number;
}
また、以下の例のように、プロパティの型に他のインターフェースを指定して、ネストさせることも可能です。
【サンプルコード】
interface Score {
english: number;
math: number;
science: number;
}
interface Student {
name: string;
age: number;
score: Score;
}
定義したinterfaceを使用する
インターフェースの定義が完了したら、実際に使用したいオブジェクトやクラスに実装します。
例えば以下のように、インターフェースを使用してオブジェクト型を定義することができます。
【サンプルコード】
interface Student {
name: string;
age: number;
}
let taro: Student = {
name: "Taro Yamada",
age: 15
};
クラスにインターフェースを実装する場合は、「implements」 キーワードを使用します。
【サンプルコード】
interface Human {
name: string;
age: number;
sayHello(): void;
}
class Student implements Human {
name: string;
age: number;
constructor(name: string, age: number) {
this.name = name;
this.age = age;
}
sayHello() {
console.log(`こんにちは、私の名前は${this.name}です。年齢は${this.age}歳です。`);
}
}
インターフェースは、複数指定することも可能です。
その場合は 「,」 で区切って記述します。
【サンプルコード】
interface Human {
name: string;
age: number;
}
interface greet {
sayHello(): void;
}
class Student implements Human, Greet {
name: string;
age: number;
constructor(name: string, age: number) {
this.name = name;
this.age = age;
}
sayHello() {
console.log(
`こんにちは、私の名前は${this.name}です。年齢は${this.age}歳です。`,
);
}
}
const taro = new Student("太郎", 20);
taro.sayHello();
【実行結果】
こんにちは、私の名前は太郎です。年齢は20歳です。
いずれも、指定のインターフェースに定義されているプロパティやメソッドが含まれていないと、コンパイル時にエラーが発生します。
関数型のインターフェイスを宣言する
TypeScriptでは、関数を型として定義する場合にもインターフェースを活用することができます。
関数のインターフェースを定義する際は、以下のような構文で、引数と戻り値の型を定義します。
【基本構文】
interface 関数名 {
(引数1: 型1, 引数2: 型2, ...): 戻り値の型;
}
関数が受け取る引数や戻り値の型などを厳密に指定することで、間違った型のデータを関数に渡すことを防ぎ、安全性を向上させることができます。
また、インターフェースを定義することで、関数がどのような引数を取り、どのような値を返すかを明示することができるため、コードの可読性が向上するという利点もあります。
以下は、簡単なサンプルコードです。
【サンプルコード】
interface FunctionSayHello {
(name: string): string;
}
interface FunctionSum {
(x: number, y: number): number;
}
const sayHello: FunctionSayHello = function(name: string) {
return `こんにちは、私の名前は${name}です。`;
};
const sum: FunctionSum = function(x: number, y: number) {
return x + y;
};
console.log(sayHello("山田太郎"));
console.log(sum(2, 3));
【実行結果】
こんにちは、私の名前は山田太郎です。
5
readonlyで読み取り専用のプロパティを宣言する
TypeScriptのインターフェースでは、プロパティ名の前に 「readonly」 修飾子をつけることで、読み取り専用のプロパティとして定義することができます。
以下の例を見てみましょう。
【サンプルコード】
interface Human {
readonly name: string;
age: number;
}
let taro: Human = {
name: "山田太郎",
age: 15
};
taro.name = "田中太郎";
taro.age = 20;
【実行結果】
error TS2540: Cannot assign to 'name' because it is a read-only property.
上記のサンプルコードを実行すると、このようにエラーが発生します。
letで変数を宣言しているため、本来であれば値の上書きが可能なのですが、nameプロパティが読み取り専用のため不具合が起きているのです。
このように、一部の値のみを上書き不可としたい場合などに便利な機能です。
interfaceの継承とオーバーライド
interfaceに似た機能に、type(型エイリアス)というものがあります。
基本的な仕様が似ているこの2つですが、継承やオーバーライドの点において、記述方法や動作が異なります。
まずは、それぞれの継承方法から見ていきましょう。
interfaceの場合は、「extends」 キーワードを使用することで継承ができます。
【サンプルコード】
interface Job {
job: string;
}
interface Human extends Job {
name: string;
}
上記の例では、「Job」 インターフェースを継承しているため、結果として 「Human」 インターフェースは job と name の2つのプロパティを持つことになります。
一方、typeでは継承を行うことができませんが、代わりに交差型 (&) を使用することで似た機能を実現することができます。
【サンプルコード】
type Job = {
job: string;
};
type Human = Job & {
name: string;
};
interfaceでプロパティのオーバーライドを行う場合に、互換性のない型を指定するとエラーが発生します。
例えば、以下のような例です。
【サンプルコード】
interface Human {
name: string;
age: number;
}
interface Student extends Human {
name: number;
age: number;
class: number;
}
【実行結果】
error TS2430: Interface 'Student' incorrectly extends interface 'Human'.
Types of property 'name' are incompatible.
Type 'number' is not assignable to type 'string'.
一方、typeの場合はコンパイルエラーが発生せず、never型として処理されます。
コンパイル時にオーバーライドのミスを防ぎたい場合は、typeよりも interfaceの方が使用に適しています。
また、次の項目でも詳しく解説しますが、TypeScriptの標準ライブラリで使用されている declaration mergingというテクニックにより、interfaceでは同名での定義を複数行った場合に内容がマージされるという特徴があります。
この特徴は typeには無い機能のため、拡張性を重要視する場合も interfaceの使用がより適しています。
interfaceの宣言をマージする
先ほども解説したように、interfaceは 「Declaration Merging」 というテクニックにより、同じ名前で宣言された2つ以上のインターフェースを1つのインターフェースとして統合(マージ)するという特徴を持っています。
以下の例を見てみましょう。
【サンプルコード】
interface Human {
name: string;
}
interface Human {
age: number;
}
const human: Human = {
name: "山田太郎"
};
【実行結果】
error TS2741: Property 'age' is missing in type '{ name: string; }' but required in type 'Human'.
上記のコードを実行すると、humanオブジェクトに ageプロパティが定義されていないとして、エラーが出てしまいます。
このエラーは、宣言のマージにより、Humanインターフェースが持つプロパティが name と age の2つとなったために発生しています。
このように、interfaceで同名での宣言を複数行うと、自動で内容が1つに統合されます。
まとめ
いかがでしたか?今回は、interfaceを使用して型定義をする方法について解説しました。
型安全性やコードの可読性の観点において、インターフェースは非常に重要な機能ですので、ぜひこの記事も参考にしながら、実際の開発に活用してみてください。
TypeScriptの勉強方法は?
書籍やインターネットで学習する方法があります。昨今では、YouTubeなどの動画サイトやエンジニアのコミュニティサイトなども充実していて多くの情報が手に入ります。
そして、より効率的に知識・スキルを習得するには、知識をつけながら実際に手を動かしてみるなど、インプットとアウトプットを繰り返していくことが重要です。特に独学の場合は、有識者に質問ができたりフィードバックをもらえるような環境があると、理解度が深まるでしょう。
ただ、TypeScriptに限らず、ITスキルを身につける際、どうしても課題にぶつかってしまうことはありますよね。特に独学だと、わからない部分をプロに質問できる機会を確保しにくく、モチベーションが続きにくいという側面があります。独学でモチベーションを維持する自信がない人にはプログラミングスクールという手もあります。費用は掛かりますが、その分スキルを身につけやすいです。しっかりと知識・スキルを習得して実践に活かしたいという人はプログラミングスクールがおすすめです。
プログラミングスクールならテックマニアがおすすめ!

ITスキル需要の高まりとともにプログラミングスクールも増えました。しかし、どのスクールに通うべきか迷ってしまう人もいるでしょう。そんな方にはテックマニアをおすすめします!これまで多くのITエンジニアを育成・輩出してきたテックマニアでもプログラミングスクールを開講しています。
<テックマニアの特徴>
・たしかな育成実績と親身な教育 ~セカンドキャリアを全力支援~
・講師が現役エンジニア ~“本当”の開発ノウハウを直に学べる~
・専属講師が学習を徹底サポート ~「わからない」を徹底解決~
・実務ベースでスキルを習得 ~実践的な凝縮カリキュラム~
このような特徴を持つテックマニアはITエンジニアのスタートラインとして最適です。
話を聞きたい・詳しく知りたいという方はこちらからお気軽にお問い合わせください。