今回はオブジェクトの型付けを行うインターフェース(Interface)について解説したいと思います。インターフェースを使うことで、よりスッキリとした可読性の高いコードを書くことができるので、ぜひこの機会にマスターしましょう。
インターフェース(Interface)とは
インターフェースとはオブジェクトの型付けを行うことができる機能です。具体的には、メンバの変数やメソッドなどを一箇所で型付けすることができます。
インターフェースの基本形は以下になります。
interface インターフェイス名 {
メンバ変数名: メンバ変数の型名;
メンバ関数名(引数名: 引数の型名): 戻り値の型名;
}
メンバとはクラス内に定義されている変数やメソッドの総称です。
以下のコードでは、変数fruitsnameとsay()メソッドがFruitsクラスのメンバということになります。
class Fruits {
fruitsname: string;
constructor(fruitsname: string) {
this.fruitsname = fruitsname;
}
say(): void {
console.log("私は" + this.fruitsname + "を食べたい");
}
}
コードで見てみる
インターフェースについて実際のコードでも見ていきましょう。
例えば、2つの言葉を組み合わせるメソッド(mergeWord)が定義されているとします。
function mergeWord(result: {x: string, y: string}) {
return result.x + result.y;
}
var result = {
x: "こんにちは。",
y: "今日もいい天気ですね。"
}
console.log(mergeWord(result));
=> こんにちは。今日もいい天気ですね。
上記のように「xはstring型、yもstring型」というような単純なコードであればそのままでも良いかもしれませんが、もっとコードが複雑になった場合は引数の型付けをまとめて行いたいですよね。
この場合に使えるのがインターフェースという機能です。
前述した通り、インターフェースとはオブジェクトを1箇所にまとめて定義できる機能なので、今回はそれを使ってよりスッキリとしたコードを書いてみましょう。
interface Result {
x: string,
y: string
}
function mergeWord(result: Result) {
return result.x + result.y;
}
var result = {
x: "こんにちは。",
y: "今日もいい天気ですね。"
}
console.log(mergeWord(result));
=> こんにちは。今日もいい天気ですね。
このように1箇所に変数をまとめておくことで、可読性が高いコードを書くことができました。これがインターフェースの基本的な使い方となります。
インターフェースの継承
インターフェースもクラスと同様に継承させることができます。
クラスの継承の場合は1つのクラスからしか継承できませんでしたが、インターフェースに関しては複数のインターフェースから継承することができるという点に注意してください。

ではインターフェースの継承をコードで見ていきましょう。
interface FirstWord {
x: string;
}
interface SecondWord {
y: string;
}
interface Sentence extends FirstWord, SecondWord {
sentence: string;
}
function mergeWord(result: Sentence) {
return result.x + result.y + result.sentence;
}
var result = {
x: "こんにちは。",
y: "今日もいい天気ですね。",
sentence: "そう思いますよね?"
}
console.log(mergeWord(result));
=> こんにちは。今日もいい天気ですね。そう思いますよね?
コードを分解して詳しく見ていきます。
まずはインターフェースを使用し、xとyの型付けを行なっています。
interface FirstWord {
x: string;
}
interface SecondWord {
y: string;
}
続いて、先ほどのインターフェース(FirstWordとSecondWord)を継承したSentenceというインターフェースを定義しています。こうすることでSentenceには、xとyとsentenceを持ったインターフェースを作成することができました。
interface FirstWord {
x: string;
}
interface SecondWord {
y: string;
}
interface Sentence extends FirstWord, SecondWord {
sentence: string;
}
あとはメソッドの引数としてSentenceを定義することで、xとyとsentenceを使用した文言を作成することが可能になります。
function mergeWord(result: Sentence) {
return result.x + result.y + result.sentence;
}
このようにインターフェースの継承を使用することでコードの重複を避けることができ、大規模開発に適したプログラムを書くことができます。
インターフェースのオプション
続いて、インターフェースのオプション化について解説したいと思います。インターフェースのプロパティは、メソッドの引数と同様にオプションにすることができます。

先ほどのコードのインターフェース(Sentence)をオプション化してみましょう。
interface FirstWord {
x: string;
}
interface SecondWord {
y: string;
}
interface Sentence extends FirstWord, SecondWord {
sentence?: string;
}
function mergeWord(result: Sentence) {
if (result.sentence) {
return result.x + result.y + result.sentence;
} else {
return result.x + result.y
}
}
var result = {
x: "こんばんわ。",
y: "今日も寒いですね。",
}
console.log(mergeWord(result));
=> こんばんわ。今日も寒いですね。
インターフェースとクラス
ここまででインターフェースの概要と継承、オプション化について解説しました。最後はインターフェースとクラスについて見ていきましょう。
インターフェースはクラスと組み合わせると、インターフェースの中のプロパティをクラスの方で必ず実装しなければならないという決まりがあります。
以下に基本的なクラス宣言をしたコードを持ってきました。
class Fruits {
fruitsname: string;
constructor(fruitsname: string) {
this.fruitsname = fruitsname;
}
say(): void {
console.log("私は" + this.fruitsname + "を食べたい");
}
}

上記のFruitsクラスに何らかの変数やメソッドを必ず実装させたい場合は、インターフェースを以下のように定義します。
interface DislikeFruits {
dislikefruits: string;
saydislikefruits(): void;
}
class Fruits {
fruitsname: string;
constructor(fruitsname: string) {
this.fruitsname = fruitsname;
}
say(): void {
console.log("私は" + this.fruitsname + "を食べたい");
}
}
その後、インターフェースを持ったクラスを実装するため「implements DislikeFruits」と記載します。こうすることで、Fruitsクラスは必ず「変数dislikefruits」と「メソッドsaydislikefruits()」を持っていなければならなことになります。
interface DislikeFruits {
dislikefruits: string;
saydislikefruits(): void;
}
class Fruits implements DislikeFruits {
fruitsname: string;
constructor(fruitsname: string) {
this.fruitsname = fruitsname;
}
say(): void {
console.log("私は" + this.fruitsname + "を食べたい");
}
}
ここで試しにコンパイルを実行してみましょう。すると、以下のようなエラーが出力され、コンパイルが正常に行われないかと思います。
% tsc test.ts
=> error TS2420: Class 'Fruits' incorrectly implements interface 'DislikeFruits'.
このエラーを回避するには「変数dislikefruits」と「メソッドsaydislikefruits()」を実装すれば解消できます。
interface DislikeFruits {
dislikefruits: string;
saydislikefruits(): void;
}
class Fruits implements DislikeFruits {
fruitsname: string;
dislikefruits: string = "柿";
constructor(fruitsname: string) {
this.fruitsname = fruitsname;
}
say(): void {
console.log("私は" + this.fruitsname + "を食べたい");
}
saydislikefruits(): void {
console.log("私は" + this.dislikefruits + "が嫌いだ");
}
}
このように必ず実装しなければならない機能はインターフェースを用いることで実現することができます。
まとめ
- インターフェースとはオブジェクトの型付けを行うことができる機能。
- メンバとはクラス内に定義されている変数やメソッドの総称。
- インターフェースを定義する際は「interface ~」と記述する。
- インターフェースは複数のインターフェースから継承することができる。
- インターフェースの継承はクラスの継承と同様にextendsを付与してあげる必要がある。
- メソッドのプロパティにクエッションマーク(?)を付与することでオプション化にすることができる。
- インターフェースはクラスと組み合わせると、インターフェースの中のプロパティをクラスの方で必ず実装しなければならなくなる。
参考
インターフェイス 宣言:
https://docs.solab.jp/typescript/interface/declaration/
インターフェース:
https://typescript-jp.gitbook.io/deep-dive/type-system/interfaces
Typescriptのinterfaceの使い方:
https://qiita.com/nogson/items/86b47ee6947f505f6a7b
今回はオブジェクトの型付けを行うインターフェース(Interface)について解説しました。ぜひインターフェースを使いこなし、大規模開発にも耐えうるプログラムを設計していきましょう。