TypeScript typeとinterfaceの違いと使い分けを解説

2023.08.05 に更新記事は 10 分で読めます
サムネイル画像

この記事ではTypeScriptのtypeとinterfaceの違いについて、実践的な例を交えて解説していきます。

これから、結論、TypeScriptのtypeの説明、TypeScriptのinterfaceの説明、typeとinterfaceの違い、どちらを使うべきか、という順番でお話しします!

結論

TypeScriptのtypeとinterfaceはどちらも 型を定義するための機能 です。

似ている機能だからこそどちらを使えばいいのか悩みますよね。
それぞれ使い方や適用範囲が異なりますが、基本的にはどちらをつかっても問題はない と思います。

個人的にはあとから勝手に型情報が変更されたりしないtypeの方が好みだったりします...!

TypeScriptのtypeの説明

それでは、まずはTypeScriptのtypeについて説明していきます。

TypeScriptのtypeは 型エイリアス とも呼ばれ、新しい型を定義する 際に使います。

例えば次のようにtypeを使って、新しい型を定義できます。

type User = {
  name: string;
  age: number;
};

上記のコードでは name プロパティが文字列型、age プロパティが数値型のオブジェクトを表す新しい型 User を定義しています。

また、typeは 既存の型を組み合わせて新しい型を作る こともできます!

type Animal = "Dog" | "Cat" | "Bird";

この例では Animal という新しい型を定義して、この型には DogCatBird のいずれかの値を入れることができます。
指定した値しか入れることができない新しい型、ということですね。

さらに、タプル型を使って 要素数が固定された配列型 を定義することができます。

type Point = [number, number];

この例では Point という新しい型を定義して、この型は2つの数値要素からなる配列(タプル)を表します。
2つ以上の数値を代入することができない配列型ということですね。

TypeScriptのinterfaceの説明

TypeScriptのinterfaceについてはどうでしょうか?

TypeScriptのinterfaceは オブジェクトの型を定義する 際に使います。
例えば、次のようにinterfaceを使ってオブジェクトの型を定義できます。

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

先ほどのtypeの例と同じように、name プロパティが文字列型、age プロパティが数値型のオブジェクトを表す型 User を定義しています。
比べてみるとtypeとは書き方が少し違いますよね。

また、interfaceは 継承を使って他のinterfaceから型を引き継ぐ ことができます。
これによって既存の型を再利用して、新しい型を定義することが容易になります。

interface Animal {
  species: string;
  sound: string;
}

interface Dog extends Animal {
  breed: string;
}

上記のコード例では Animal インターフェースを定義した後、Dog インターフェースで Animal を継承しています。
Dog インターフェースは Animal のプロパティに加えて breed プロパティも持っています。

interfaceは継承で他のinterfaceから型を引き継げますが、実はtypeとinterfaceはどちらも ユーティリティ型 という型を使用することで同様に既存の型を引き継いで使用することもできます。

これについては以下の記事で詳しくまとめています!

typeとinterfaceの違い

illust

それでは、typeとinterfaceの違いを具体的なコードを使って詳細に説明します。

interfaceの特徴

  1. オブジェクトの型定義や継承ができる

interfaceの説明でもご紹介したようにinterfaceは既存のオブジェクトの型を引き継いで新しい型定義を作成することができます。

interface Vehicle {
  wheels: number;
  speed: number;
}

interface Car extends Vehicle {
  doors: number;
}

interface Motorcycle extends Vehicle {
  type: 'cruiser' | 'sport' | 'dirt';
}

const myCar: Car = {
  wheels: 4,
  speed: 120,
  doors: 4,
};

const myMotorcycle: Motorcycle = {
  wheels: 2,
  speed: 180,
  type: 'sport',
};

このコード例では最初に Vehicle インターフェースを定義し、その後 CarMotorcycle インターフェースで Vehicle を継承しています。

Car インターフェースは Vehicle のプロパティに加えて、doors プロパティを持っています。
一方、Motorcycle インターフェースは Vehicle のプロパティに加えて typeプロパティを持っています。

  1. 宣言のマージができる

同名のインターフェースを複数回定義することでそれらが自動的にマージ(1つにまとめる)されます。

interface User {
  name: string;
}

interface User {
  age: number;
}

// 結果的にUserインターフェースは以下のようになります
// interface User {
//   name: string;
//   age: number;
// }

この例では User インターフェースが二度宣言されていますが、TypeScriptは自動的にマージして nameage のプロパティを持つ User インターフェースとして定義されます。

typeの特徴

  1. ユーティリティ型を使って型を拡張できる

typeはinterfaceのように継承を使うことはできませんが、ユーティリティ型を使うことで既存の型定義を再利用して新しい型を定義することができます!

type User = {
  name: string;
  age: number;
};

type PartialUser = Partial<User>;

// 結果的にPartialUser型は以下のようになります
// type PartialUser = {
//   name?: string;
//   age?: number;
// }

この例では User 型を定義した後、Partial ユーティリティ型を使って PartialUser 型を定義しています。

PartialUser は最初に定義した User と比較して nameage プロパティが任意項目となっています。
name?: string のように、 ? がつくことで任意項目であることを意味しているわけですね。

  1. 柔軟な型定義ができる

typeでは ジェネリクス という型を使用することで柔軟に型定義をすることができます。
最初は少し難しく感じることがあるかと思いますが、使いこなすととても便利な機能です!

type ApiResponse<T> = {
  status: 'success' | 'error';
  data?: T;
  message?: string;
}

type UserData = {
  id: number;
  name: string;
}

const response: ApiResponse<UserData> = {
  status: 'success',
  data: {
    id: 1,
    name: 'Alice',
  },
};

このコードでは、ジェネリクス型を用いて ApiResponse 型を定義しています。

type ApiResponse<T> と書くことでこれはジェネリクス型であることを宣言しているわけですね。
この ApiResponse 型は呼び出すときに ApiResponse<UserData> のように <> 内の T に型を書くことで、自動的に data プロパティの型に指定した型定義が使用されます。

これにより ApiResponse 型は任意の型 T を持つことができるため、非常に柔軟な型定義ができます!

どちらを使うべきか

これまで紹介したように、TypeScriptのtypeとinterfaceはどちらも型を定義するための機能ですが使い方や特徴が少し違います。

interfaceは オブジェクトの型定義や継承 をサポートしているため、拡張性と再利用性が高くなるなります。
一方、typeは ユーティリティ型を使って型を拡張 することができ、ジェネリクスを使うことで柔軟に型を定義 することが可能です。

結果として、typeとinterfaceはどちらを使っても問題ありません!

現在のプロジェクトで使用している方に統一したり、個人的に使いやすいと感じたほうを使うのが良いと思います。

ぜひこの記事の内容を今後のプログラミングに役立ててくださいね!

プロフィールアイコン

Syuu

フロントエンドが好きなWEBエンジニア Next.js / React / TypeScript

SHARE