TypeScriptを学び始めると、すぐに「interface」という言葉に出会いますよね。

interfaceってよく見かけるけど、そもそも何をするためのもの?
オブジェクトの型を書くのに、interfaceって必要なの?
interfaceとtypeって何が違うの?どっちを使えばいい?

この記事では、TypeScriptのinterfaceが「何者か」という基本的な概念から、実際の書き方・使い方まで順番に説明します。

この記事はこんな人におすすめ!
  • TypeScriptのinterfaceが何なのかよくわからない方
  • interfaceの基本的な書き方を知りたい方
  • オブジェクトに型を付ける方法をこれから学ぶ方
  • string・numberなどの基本的な型はなんとなく知っている方

この記事を読み終えると、interfaceの基本構文と「なぜinterfaceを使うのか」が理解できるようになります。実際にオブジェクトへ型を付ける書き方もコード例で確認できるので、そのまま手を動かして試してみてください。

それでは、順を追って詳しく見ていきましょう!

まずは動画解説を観る

TypeScriptのinterfaceとは

interfaceとは、オブジェクトの「形」に名前をつけて定義するための仕組みです。「このオブジェクトはどんなプロパティを持つか」を型として書き出して、名前を付けて使い回せるようにするものです。

言葉だけだとピンとこないと思うので、まず「interfaceがないとどうなるか」から見てみましょう。

interfaceを使う前との比較 — インライン型定義の問題

TypeScriptでは、オブジェクトに直接型を書くことができます。たとえばこんな感じです。

function greet(user: { name: string; age: number }) {
  console.log(`${user.name}さん、こんにちは`);
}

1つの関数だけなら、これで問題ありません。でも、同じ形のオブジェクトを別の関数でも使いたくなったらどうなるでしょう?

function greet(user: { name: string; age: number }) {
  console.log(`${user.name}さん、こんにちは`);
}

function showProfile(user: { name: string; age: number }) {
  console.log(`名前: ${user.name}, 年齢: ${user.age}`);
}

同じ { name: string; age: number } を2回書くことになってしまいました。関数が増えるほど、この繰り返しが増えていきます。さらに、「ageをnumberからstringに変えたい」となったとき、すべての箇所を探して書き直す必要があります。

この「同じ型を何度も書く」問題を解決するのがinterfaceです。

interfaceで型を「名前付きで定義する」とはどういうことか

先ほどの例をinterfaceを使って書き直してみます。

interface User {
  name: string;
  age: number;
}

function greet(user: User) {
  console.log(`${user.name}さん、こんにちは`);
}

function showProfile(user: User) {
  console.log(`名前: ${user.name}, 年齢: ${user.age}`);
}

User という名前でオブジェクトの型を1か所にまとめられました。型を変えたいときも User の定義を1か所直すだけで済みます。

これがinterfaceの本質です。「オブジェクトの型に名前をつけて、再利用できるようにする」こと。 これを頭に置いておくと、以降の説明がスムーズに入ってきます。

interfaceの基本的な書き方

概念が掴めたところで、実際の書き方を見ていきます。

プロパティを定義する

interfaceは interface キーワードのあとに名前を書き、{} の中にプロパティを列挙します。

interface User {
  name: string;
  age: number;
  email: string;
}

各プロパティは プロパティ名: 型 の形で書きます。プロパティの区切りはセミコロン(;)が一般的ですが、カンマ(,)でも動作します。

interfaceの名前は慣習として先頭を大文字にしますUserProductApiResponse など)。

オプショナルプロパティ(?)で任意のプロパティを表現する

「このプロパティはあってもなくてもいい」というケースがあります。そのときはプロパティ名のあとに ? を付けます。

interface User {
  name: string;
  age: number;
  email?: string; // あってもなくてもOK
}

email?: string と書くことで、このプロパティは string または undefined(存在しない)を許容します。

const user1: User = { name: "田中", age: 25 };             // emailなしでもOK
const user2: User = { name: "鈴木", age: 30, email: "suzuki@example.com" }; // emailありもOK

email がないオブジェクトも、ある オブジェクトも、どちらも User 型として扱えます。

? を付けたプロパティにアクセスするときは、「値が存在しないかもしれない」ことを意識する必要があります。emailundefined のまま使おうとするとエラーになることがあります。

readonlyで読み取り専用のプロパティを定義する

プロパティ名の前に readonly を付けると、そのプロパティは定義後に書き換えられなくなります。

interface User {
  readonly id: number; // 一度セットしたら変更不可
  name: string;
  age: number;
}

const user: User = { id: 1, name: "田中", age: 25 };

user.name = "鈴木"; // OK
user.id = 2;        // エラー! idはreadonlyなので変更できない

「このプロパティは変えてはいけない」という意図をコードで表現できるのが readonly の役割です。たとえばデータベースのIDなど、一度発行したら変えたくない値に使うのが典型的なパターンです。

interfaceの実際の使い方

書き方がわかったところで、実際にどう使うかを見ていきます。

変数への型注釈として使う

定義したinterfaceを変数の型として使うには、変数名のあとに : インターフェース名 を付けます。

interface User {
  name: string;
  age: number;
}

const user: User = {
  name: "田中",
  age: 25,
};

userUser 型として定義されているので、nameage も正しい型の値が必要です。もし age に文字列を入れようとすると、TypeScriptがすぐにエラーを出してくれます。

const user: User = {
  name: "田中",
  age: "二十五歳", // エラー! ageはnumberが必要
};

型が合わないコードは書いた瞬間に検出されるので、実行前にバグを防げます。 これがTypeScriptのinterfaceを使う大きなメリットです。

関数の引数の型として使う

最もよく使われる場面が、関数の引数にinterfaceを指定することです。

interface User {
  name: string;
  age: number;
}

function greet(user: User): string {
  return `${user.name}さん、こんにちは!`;
}

const user: User = { name: "田中", age: 25 };
console.log(greet(user)); // "田中さん、こんにちは!"

関数の引数に User 型を指定することで、「この関数には name(string)と age(number)を持つオブジェクトを渡してね」という制約を明示できます。

間違ったオブジェクトを渡そうとすれば、TypeScriptが教えてくれます。

greet({ name: "田中" }); // エラー! ageが足りない
greet({ name: "田中", age: 25, score: 100 }); // エラー! Userにscoreというプロパティはない

引数の型をinterfaceで定義しておくと、呼び出し側の書き間違いをコンパイル時に発見できます。

interfaceを使うメリット — 型の再利用と可読性

ここまで見てきた内容を整理すると、interfaceを使うメリットは大きく2つです。

1つ目:型の再利用性

同じ形のオブジェクトを何度も定義する必要がなくなります。型の定義を変えるときも1か所直すだけで済むので、変更に強いコードになります。

2つ目:可読性

{ name: string; age: number; email?: string } と書くより、User と書いたほうがコードが読みやすくなります。型の名前がドキュメントの役割を果たしてくれるので、「このオブジェクトは何なのか」が一目でわかります。

コードが大きくなればなるほど、この2つの恩恵が大きくなります。最初は「直接書いても同じでは?」と思うかもしれませんが、ファイルをまたいで同じ型を使い回す場面が増えてくると、interfaceの便利さが実感できるはずです。

typeとの違い・使い分けはどう考える?

ここまで読んでいると、「typeエイリアスという書き方もあると聞いたけど、interfaceとどう違うの?」と気になった方もいると思います。

TypeScriptには type という書き方もあり、オブジェクト型の定義に限っていえばinterfaceと同じことができます。

// interfaceで書く場合
interface User {
  name: string;
  age: number;
}

// typeで書く場合
type User = {
  name: string;
  age: number;
};

どちらで書いても、変数や関数の引数の型として使う分には同じように動きます。

大きな違いとしてよく挙げられるのは次の2点です。

  • interfaceは同名で複数回宣言すると自動的にマージされる(typeは同名を2回書くとエラーになる)
  • typeはオブジェクト以外の型(ユニオン型やプリミティブ型など)にも名前を付けられる

「結局どっちを使えばいい?」という点については、TypeScript公式ハンドブック(Everyday Types)にこんな記述があります。

For the most part, you can choose based on personal preference, and TypeScript will tell you if it needs something to be the other kind of declaration. If you would like a heuristic, use interface until you need to use features from type.
引用:TypeScript Handbook – Everyday Types

つまり「基本的には好みで選んでOK。目安としてはtypeの機能が必要になるまでinterfaceを使え」というのが公式の立場です。「interfaceを使っておけばOK」はあくまで慣習やチームルールの話ではなく、公式が推奨している目安でもあります。

【付録】さらに学びを深めるためのリソース


さらにTypescriptの学習を進めたい方のために、いくつかのリソースを紹介します。
これらのリソースを活用することで、TypeScriptの型システムについてより深い知識を得ることができるでしょう。

おすすめの書籍

ゼロからわかる TypeScript入門


技術評論社から出版されている「ゼロからわかる TypeScript入門」は、プログラミング初心者や本職プログラマーではない方を主な対象にした入門書です。

変数・条件分岐・ループといった基本から、クラスやインターフェース、モジュールまで段階的に学べる構成になっています。最終章ではWeb APIとJSONを使った非同期Webアプリの作成も体験できるので、「実際に動くものを作る」ところまで到達できます。

プロを目指す人のためのTypeScript入門


技術評論社の「プロを目指す人のためのTypeScript入門 安全なコードの書き方から高度な型の使い方まで」、通称 ブルーベリー本 です。
JavaScriptの仕様とTypeScript独自の機能を両方押さえつつ、リテラル型・ユニオン型・keyof型・ジェネリクスなど、高度な型表現まで踏み込んで解説しています。TypeScriptの型システムの表現力を本格的に学べる一冊です。

オンラインで参照できる公式ドキュメント

TypeScript公式ハンドブック


https://www.typescriptlang.org/docs/
TypeScriptの公式ドキュメントです。
intersection型を含む、すべての型システムの機能について詳細な説明があります。

TypeScript Deep Dive


https://basarat.gitbook.io/typescript/
TypeScriptの深い部分まで掘り下げて解説しているオンラインブックです。
無料で読むことができ、intersection型についても詳しく説明されています。

TypeScriptの学習は終わりがありません。
新しい機能が常に追加され、より良い書き方が発見されています。
継続的に学習を続けることで、より良いTypeScriptプログラマーになれるはずです。


まとめ — TypeScript interfaceの基本をおさらい

この記事で説明した内容を振り返ります。

  • interfaceとは、オブジェクトの型に名前を付けて定義する仕組み
  • interface 名前 { プロパティ名: 型 } という形で書く
  • プロパティに ? を付けるとオプショナル(任意)になる
  • readonly を付けると読み取り専用になる
  • 変数の型注釈・関数の引数の型として使うのが基本的な使い方
  • 型を1か所にまとめることで、再利用しやすく・変更に強いコードになる

interfaceはTypeScriptでオブジェクトを扱ううえで欠かせない仕組みです。最初は「インラインで書いても同じでは?」と感じるかもしれませんが、同じ型を複数の場所で使い始めると、interfaceの便利さが実感できるはずです。まずはこの記事のコード例を参考に、手を動かしてみてください。

※本記事の本文案はAIを活用して作成していますが、記載している内容およびコードは筆者が実際に調査、検証・実行し、内容の正確性を確認した上で公開しています。