TypeScriptの型エイリアス:定義と使用方法、インターフェイスとの違い

TypeScript

TypeScriptの型エイリアスは、既存の型に別名(エイリアス)を付ける機能です。
繰り返し使用される複雑な型などに簡潔な名前を付けることで、コードの可読性と保守性を向上させることができます。

型エイリアスとインターフェイスは、どちらも型を定義するために使用されますが、それぞれ異なる特性と用途を持っています。

型エイリアスの定義

型エイリアスは、typeキーワードを使用して定義します。

以下にシンプルな例を示します。

TypeScript
type Point = {
  x: number;
  y: number;
};

const myPoint: Point = { x: 10, y: 20 };

この記述により、型エイリアス Point は、数値型の変数 x と数値型の変数 y を持つ型の別名となります。

型エイリアスの使用方法

型エイリアスを用いることで、プリミティブ型をはじめ、オブジェクト型、ユニオン型、タプル型など、さまざまな型のエイリアスを作成できます。

プリミティヴ型のエイリアス

「プリミティヴのような元々シンプルな型にわざわざ別名を付けることに意味やメリットはあるのか?」と思われる方もいらっしゃるかもしれません。

はい、意味やメリットはありますので、以下にリストアップします。

  1. 可読性の向上
    • プリミティヴ型自体は単純ですが、その型が表す意味が文脈によって異なる場合があります。型エイリアスを使用することで、その型がどのような意味を持つのかを明確にすることができます。 例えば、number型がミリ秒を表す場合、type Milliseconds = number;と定義することで、コードを読む人がその意図を理解しやすくなります。
  2. 型の再利用
    • 同じプリミティヴ型を複数の場所で使用する場合、型エイリアスを定義することで、型定義を一箇所にまとめることができます。 これにより、型の変更があった場合に、型エイリアスを変更するだけで済み、コードの保守性を向上させることができます。
  3. 型の制限
    • プリミティヴ型を特定の範囲に制限したい場合に、型エイリアスと組み合わせることで、より厳密な型定義を行うことができます。 例えば、0から100までの整数を表す型を定義したい場合、型エイリアスとカスタム型ガードを組み合わせることで、その範囲外の値を許可しないようにすることができます。
  4. 意味の明確化
    • 例えば、string型が特定の形式の文字列を表す場合、型エイリアスを使用することで、その形式を明確にすることができます。 例としては、type Email = string;とすることで、その文字列がメールアドレスであることを示したり、正規表現と組み合わせることで、メールアドレスの形式を検証することもできます。

プリミティヴ型自体は単純ですが、その型が表す意味が文脈によって異なる場合があります。型エイリアスを使用することで、その型がどのような意味を持つのかを明確にすることができます。

具体的な使用例

TypeScript
// ミリ秒を表す型エイリアス
type Milliseconds = number;

// 年齢を表す型エイリアス
type Age = number;

// メールアドレスを表す型エイリアス
type Email = string;

function delay(time: Milliseconds) {
  setTimeout(() => {
    console.log("Delayed for", time, "milliseconds");
  }, time);
}

const userAge: Age = 30;
const userEmail: Email = "test@example.com";

delay(1000);

オブジェクト型のエイリアス

JavaScriptのオブジェクト構造(プロパティとその型)を1つの型にまとめて別名を付けることができます。

TypeScript
type Person = {
  name: string;
  age: number;
};

const john: Person = { name: "John", age: 30 };

ユニオン型のエイリアス

ユニオン型については、こちらの記事で解説しています。

TypeScript
type StringOrNumber = string | number;

let value: StringOrNumber = "Hello";
value = 42;

タプル型のエイリアス

タプル型は、要素の型と数が固定された配列です。
タプルの各要素は、定義された型に対応する値を持つ必要があります。

同一の型を持つタプル

TypeScript
type Coordinate = [number, number];

const origin: Coordinate = [0, 0];

同一の型を持つタプルは、配列と似たような用途で使用されることが多く、例として次のようなケースで使用されます。

  • 座標やベクトルなど、同じ型の要素が連続する場合
  • 固定長の配列として使用する場合

異なる型を持つタプル

TypeScript
const exampleTuple: MixedTuple = ["Hello", 42, true];

console.log(exampleTuple[0]); // "Hello"
console.log(exampleTuple[1]); // 42
console.log(exampleTuple[2]); // true

異なる型を持つタプルは、構造化されたデータを扱う用途で使用されることが多く、例として次のケースで使用されます。

  • 関数の戻り値として、複数の異なる型の値を返す場合
  • 設定値やレコードなど、構造が固定されたデータを表現する場合
  • APIからのレスポンスなど、特定の構造を持つデータを扱う場合

関数型のエイリアス

TypeScript
type StringTransformer = (input: string) => string;

const toUpperCase: StringTransformer = (input) => input.toUpperCase();

ジェネリック型のエイリアス

TypeScript
type Box<T> = {
  value: T;
};

const numberBox: Box<number> = { value: 42 };

インターフェイスとの違い

型エイリアスとインターフェイスには多くの違いがありますが、まずは特に重要と思われる違いをリストアップします。

  • 拡張(継承):インターフェイスはextendsで拡張できますが、型エイリアスは交差型(&)を使用します。
  • 宣言のマージ:同じ名前のインターフェイスは自動的にマージされますが、型エイリアスはエラーになります。
  • 柔軟性:型エイリアスはより広範な型(ユニオン型、タプル型など)を扱えます。
  • 用途:インターフェイスはオブジェクトの形状定義、型エイリアスは型の別名定義に主に使われます。

続いて、両者の共通点を挙げます。

  • 両者ともオブジェクト型や関数型などを定義できる。
  • プロパティやメソッドを含む型を記述できる。
  • 型アノテーション(型注釈)として使用できる。

比較マトリックス

機能/特徴インターフェイス型エイリアス
クラスの実装を強制×
マージ(再オープン)(プロパティ・メソッドを追加可能)×
ユニオン型×
タプル型×
オブジェクトの構造定義
プリミティヴ型定義△(基本はオブジェクト用)
交差型(インターセクション型)△(拡張インターフェイスとして)
関数型△(メソッドとして可能)
複雑な型の表現△(拡張インターフェイスとして)
  • :一方のみできる
  • 〇:できる
  • △:限定的にできる
  • ×:できない

使い分けのポイント

  • インターフェイス
    • オブジェクトの構造を定義する場合や、クラスに実装を強制する場合に適しています。特に、プロパティの追加や拡張が必要な場合に便利です。
    • ユニオン型を使用できない点に注意が必要です。
  • 型エイリアス
    • より柔軟な型定義や、ユニオン型、交差型、関数型などの表現が必要な場合に適しています。
    • マージ(再オープン)できないため、一度定義された型に追加のプロパティを加えることはできません。

型エイリアスの利点と注意点

型エイリアスの利点としては、コードの可読性を向上させ、型の再利用性を高めます。
また、複雑な型を簡略化するのにも役立ちます。

ただし、注意点として、型のエイリアスは新しい型を作成するわけではないことには注意が必要です。

まとめ

型エイリアスとインターフェイスは、TypeScriptの型システムにおいて重要な役割を果たします。
それぞれの特性を理解し、適切に使い分けることで、より安全で保守性の高いコードを書くことができます。


本記事についての質問、誤りの指摘、ご意見ご感想などありましたら、ぜひコメント頂ければ幸いです。

最後までお読みいただき、ありがとうございました。

コメント

タイトルとURLをコピーしました