こんにちは。KOUKIです。
本記事では、TypeScriptのインターフェースについて、その概念や使い方をまとめています。
TypeScriptの初学者にとって有益な情報となっていると思いますので、是非ご一読ください^^
学習まとめ
環境構築
以下の記事で作成したプロジェクトを使います。
※TypeScriptが動けば問題ありません
インターフェースとは
TypeScriptのインターフェースは、「オブジェクトがどんな形であるか」定義するためのものです。
インターフェースを定義するためには、「interface」キーワードを用います。
1 2 3 4 5 6 7 8 9 10 |
// オブジェクトがどのような形なのか定義 // イメージとしては、オリジナルの型を作っている(そのため、構造のみ定義) interface Book { // プロパティ -> 実数値は定義できない title: string; num: number; // メソッド -> 処理は定義できない review(comment: string): void; } |
インターフェースは、構造を定義するためのものです。それは、「新しい型」を作り出しているのと同義です。
そのため、これを使ってオブジェクトの型チェックができます。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
interface Book { title: string; num: number; review(comment: string): void; } // 実装例 let book1: Book; book1 = { title: "Harry Potter", num: 10, review(comment: string) { console.log(this.title + ": " + comment); }, }; book1.review("This book is very Fantastic!"); // => Harry Potter: This book is very Fantastic! |
book1には、Bookインターフェースを型定義しました。これにより、book1は、インターフェースに定義されているプロパティやメソッドを全て実装する必要があり、どれか一つでも実装が漏れていた場合は、エラーが発生します。

インターフェースの実装
インターフェースが必要な理由

インターフェースが必要な理由は、以下の通りだと思います。
2: 共通の機能を複数のクラスに渡って実装させることができる
3: 型として定義すると意図したプロパティやメソッドを持っていることを担保できる
詳しく見ていきましょう。
以前、カスタム型というものを学びました。
カスタム型は、「type」キーワードを使って、自分が定義したい新しい型を作り出すことができます。
先ほどのインターフェースも以下のように書き換えることができます。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
// typeキーワードに書き換え type Book = { title: string; num: number; review(comment: string): void; }; // 実装例 let book1: Book; book1 = { title: "Harry Potter", num: 10, review(comment: string) { console.log(this.title + ": " + comment); }, }; |
これでもオブジェクトの型チェックができます。インターフェースとカスタム型は基本的には同じなのです。
では、何故インターフェースがあるのでしょうか。
一つの違いとして、インターフェースは、「オブジェクトの構造を定義することだけ」できます。カスタム型はオブジェクト型以外にもユニオン型などTypeScriptの様々な型を定義することができます。
つまりインターフェースを使うことは、「オブジェクトの型を定義する」という意図を明確に開発者に伝えることができます。
また、インターフェースはクラスに対して、実装を行うことができます。
実装を行うためには、「implements」キーワードを使います。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
interface Reviewable { title: string; review(comment: string): void; } class Book implements Reviewable { title: string; num: number = 0; constructor(t: string) { this.title = t; } review(comment: string) { console.log(this.title + ": " + comment); } } |
尚、インターフェースは、クラスに対して複数割り当てることができます。
1 |
class Book implements Reviewable, AnotherInterface { ... } |
そして、インターフェースを実装したクラスは、インターフェースに定義したプロパティやメソッドを必ず実装する必要があります。
加えて、クラスには、インターフェースにはない新しいプロパティやメソッドも追加できるのです。
インターフェースは、「具体的な実装に関係なく複数のクラスで同じ機能を持たせるとき」に便利ですね。抽象クラス(abstract)と少し似ています。
抽象クラスは、インターフェースと違って、抽象メソッドも具体的なメソッドも両方定義できます。また、クラスは一つのクラスのみ継承できます。
1 2 3 4 5 |
# OK class Book extends Book2 {} # NG class Book extends Book2, Book3 {} // error |
インターフェースを実装したクラスは、以下のように宣言できます。
1 2 3 |
let book1: Reviewable; // Reviewableを型にした変数を宣言 book1 = new Book("Harry Potter"); // Reviewableを実装したクラスを格納可能 book1.review("Wonderfull!"); |
このようにReviewableを型として変数に宣言すると、reviewメソッドを持つオブジェクトのみ変数に代入できるので、代入したオブジェクトは確実にreview関数を持つことになります。
これは、開発者にとって非常に便利に感じる機能なんです。
インターフェースを読み取り専用にする
インターフェースのプロパティに「readonly」キーワードをつけると読み取り専用にできます。
1 2 3 4 5 |
interface Reviewable { readonly title: string; review(comment: string): void; } |
インターフェースの継承
クラスと同様にインターフェースも継承を使うことができます。
それには、クラスと同様に「extends」キーワードを用います。
1 2 3 4 5 6 7 8 9 10 |
interface Reviewee { name: string; } // extendsキーワードで、インターフェースを継承する interface Reviewable extends Reviewee { readonly title: string; review(comment: string): void; } |
インターフェースを分けると、あるオブジェクトでは「Reviewable/Revieweeの機能が両方必要」、「他のオブジェクトではRevieweeの機能だけ必要」、など用途ごとに実装することが可能になります。
また、クラスとは違いインターフェースは複数のインターフェースを継承することができます。
1 2 3 4 5 6 7 8 9 10 11 12 13 |
interface Reviewee { name: string; } interface Drafted { draft: boolean; } interface Reviewable extends Reviewee, Drafted { readonly title: string; review(comment: string): void; } |
インターフェースを関数の型として定義する
インターフェースは、関数の型としても定義できます。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
interface Add { // 引数2, 戻り値numberの関数型を定義 (num1: number, num2: number): number; } // Add関数型で型付け let add: Add; // Add関数型と同じ構造になるように関数を定義 add = (num1: number, num2: number) => { return num1 + num2; }; // 利用する console.log(add(10, 20)); |
ちなみに、カスタム型(type)でも同じことができます。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
type Add = { // 引数2, 戻り値numberの関数型を定義 (num1: number, num2: number): number; }; // Add関数型で型付け let add: Add; // Add関数型と同じ構造になるように関数を定義 add = (num1: number, num2: number) => { return num1 + num2; }; // 利用する console.log(add(10, 20)); |
オブジェクトの定義ではないので、この場合はカスタム型を使うことが一般的のようです。
・オブジェクト以外の型を定義したい -> カスタム型を用いる

使い分けは、あくまで目安です。状況によっては異なるかもしれません。
インターフェースで任意のプロパティを設定する
インターフェースに任意のプロパティを設定することができます。
そのためには、「?」を使います。
1 2 3 4 5 6 7 |
interface Reviewable { readonly title: string; // 任意のプロパティ like?: boolean; review(comment: string): void; } |
任意のプロパティとは、実装先でこのプロパティを設定しなくてもエラーにならないという意味です。上記の例では、likeはつけてもつけなくてもOKということです。
クラスにも任意のプロパティを設定できますが、その場合はインターフェースのプロパティも任意のプロパティとする必要があります。
1 2 3 4 5 6 7 8 9 10 11 12 |
interface Reviewable { title?: string; // こちらも帰る } class Book implements Reviewable { title?: string; // 任意のプロパティ constructor(t?: string) { // こちらにも... if (t) { this.title = t; } } ... } |
おわりに
以上がインターフェースの概要と実装方法です。
インターフェースは、実装したクラスにプロパティやメソッドを強制することができます。また、オブジェクトがどのような構造であるか定義することができます。
とても強力な機能です。使いこなしてきましょう^^
インターフェースは、Go言語やJavaでも出てくるので、ここで理解すると他の言語でも理解が進みますよ!
それでは、また!
最近のコメント