型エイリアスとinterfaceについて理解しよう

Posted: August 01, 2020

この記事は前回(https://tyotto-good.com/blog/basic-type-typescript)の続きです!
TypeScriptでの基礎的な型を理解していただいた上で、今回は型エイリアスと、Interfaceについて説明していきたいと思います。

型エイリアス

変数に名前をつけて、値を代入できるのと同様に、TypeScriptでは型に名前をつけて宣言することができます。これを型エイリアス(type alias)と呼びます。宣言方法は、type 型名とします。
以下に例を示します。

type Coffee = {
  name: string,
  country: string,
  code: number,
};

新たに定義した、Coffee を利用するには、以下のようにします。

// アラビカコーヒーを定義
const arabica: Coffee = {
  name: "Arabica",
  country: "Ethiopia",
  code: 1,
}

// Coffeeで定義されていたcodeプロパティが存在しないためエラー
const american: Coffee = {
  name: "American coffee",
  country: "America"
};

新たにコーヒーの種類として、型エイリアスを利用してアラビカコーヒーを定義しています。下の例ではCoffeeの型エイリアスで指定していたcodeプロパティが欠如しているためエラーとなります。
また、JavaScriptの変数と同様に、基本同じ型を2度宣言することはできません。さらに、型エイリアスはブロックスコープなため、スコープの有効範囲はブロック内に限ります。そのため、以下のように別のブロックでは同じ型を宣言することができます。

type status = "done";
type status = "progress";
// コンパイルエラー : 2度同じ名前の型エイリアスを宣言できない

if (isStatus) {
  type status = "done";
} else {
  type status = "progress";
}
// 型エイリアスはブロックスコープなので2度同じ名前の型エイリアスを宣言したことにならない

新たにコーヒーの種類として、型エイリアスを利用してアラビカコーヒーを定義しています。下の例ではCoffeeの型エイリアスで指定していたcodeプロパティが欠如しているためエラーとなります。
また、JavaScriptの変数と同様に、基本同じ型を2度宣言することはできません。さらに、型エイリアスはブロックスコープなため、スコープの有効範囲はブロック内に限ります。そのため、以下のように別のブロックでは同じ型を宣言することができます。

type status = "done";
type status = "progress";
// コンパイルエラー : 2度同じ名前の型エイリアスを宣言できない

if (isStatus) {
  type status = "done";
} else {
  type status = "progress";
}
// 型エイリアスはブロックスコープなので2度同じ名前の型エイリアスを宣言したことにならない

interface

interface も、型エイリアスと同様に型に名前をつけることができます。型エイリアスとは微妙な違いがいくつかあるので、まずは宣言方法からみていきましょう。以下のようにinterfaceは宣言できます。

interface Person {
	name: string
	sex: string
	age: number
};

型エイリアスだと以下のように表現できます。

type Person = {
  name: string,
  sex: string,
  age: number
};

interfaceを拡張するには、extendsを用います。以下の例では、Personインタフェースを拡張したEngineerインタフェースを宣言し、利用しています。

// Personを拡張してEngineerインタフェースを定義
interface Engineer extends Person {
  language: string
}

// Personで宣言したプロパティに加えて拡張されたlanguageプロパティが使える
const Tom: Engineer = {
  name: "Tom",
  sex: "male",
  age: 20,
  language: "TypeScript"
};

同じようなことを型エイリアスでしてみます。

type Engineer = Person & {
  language: string
};

型エイリアスとinterfaceの違い

ここまではinterfaceと型エイリアスにほぼ違いがないと感じると思いますので、それらの細かな違いを説明していきます。

型エイリアスは右辺に任意の型を指定できる

先ほどinterfaceと型エイリアスとで型を拡張する例を説明しましたが、型エイリアスは型を拡張するさいに右辺に|&のような型演算子を指定することができます。しかしinterfaceは指定できないため、型エイリアスの方が汎用的であると言えます。

interfaceは拡張時に割り当て可能かチェックを行う

interfaceを拡張する場合に、拡張元のinterfaceに割り当てることができるかチェックを行います。

interface Person {
  name: string,
  sex: string
};

interface Person2 extends Person {
  name: number
}
// コンパイルエラー
// プロパティ"name"にstringが拡張元で割り当てられているため、numberを割り当てることはできない

型エイリアスの場合は型を結合してコンパイル時のエラーを出さないようにします。

type Person = {
  name: string 
}
type Person2 = Person & {
	name: number
}
// Person2の型はオーバーロードされる

同一スコープ内に同一名のインタフェースが存在すると自動でマージされる

以下のように、同一名のインタフェースが存在すると自動でマージされます。

interface Person {
	name: string
	sex: string
	age: number
};
// この段階で自動マージされる
interface Person {
  country: string
}

const john: Person = {
  name: "John",
  sex: "male",
  age: 30,
  country: "Canada"
}

一方で同じ名前の型エイリアスを宣言するとコンパイルエラーが生じてしまいます。

type Person = {
	name: string
}
type Person = {
	sex: string
}
// コンパイルエラー

以上、型エイリアスとinterfaceについてでした!
どちらもTypeScriptを扱う上では頻繁に使用するので、是非理解し、使えるようになってくださいね💪
ではまた🙌
参考 : https://qiita.com/tkrkt/items/d01b96363e58a7df830e