白猫のメモ帳

C#とかJavaとかJavaScriptとかHTMLとか機械学習とか。

TypeScriptのinterfaceとtype

こんにちは。
夕食のメニューに鍋という選択肢が入ってきてちょっと楽ちんです。
今回はinterfaceとtypeの比較をします。

interfaceっぽいのはオブジェクト型

さて、前回typeについて見ていきましたが、typeに定義できる種類にオブジェクト型というものがありました。
オブジェクト型のtypeはinterfaceと同様に抽象メソッドとフィールドを定義することができます。

interface ItemIF { 
    name: string;
    getPrice(): number; 
}
type ItemTP = { 
    name: string;
    getPrice(): number; 
};

継承と交差型

interfaceはinterfaceとtypeを継承することができます。(ややこしいのでclassの話はしないですが、正確にはclassも継承できます)
typeはinterfaceもtypeも継承することができませんが、代わりに交差型の表現ができます。
制限というよりは書き方の違いという方がしっくりくる気がします。

interface Interface1 { a : string }
type Type1 = { b : number };

// 継承できる
interface Interface2 extends Interface1, Type1 {}
// こんな文法はない
type Type2 extends Type1;
// 交差型は作れる
type Type3 = Type1 & Interface1;

拡張

同じ名前のinterfaceを複数定義した場合、その定義はマージされます。

interface Interface1 { a : string }
interface Interface1 { b : string }  // マージされるのでOK
interface Interface1 { a : string }  // すでにある定義だけど型があってるのでOK
interface Interface1 { b : number }  // すでにある定義と型があっていないのでNG

感覚としては複数のインタフェースを継承した時と同じ感じです。

interface Interface1 { a : string }
interface Interface2 { b : number }
interface Interface3 { a : string }
interface Interface4 { a : number }

interface Interface5 extends Interface1, Interface2 {}  // これはOK
interface Interface6 extends Interface1, Interface3 {}  // これもOK
interface Interface7 extends Interface1, Interface4 {}  // これはNG

typeの場合にはエラーになります。

// エラー
type Type1 = { a : string };
type Type1 = { b : number };

ユーティリティ型

オブジェクト型のtypeの使い方にユーティリティ型というものがあります。

type Item = {
    name: string;
    price: number;
};

type OptionalItem = Partial<Item>;

// こういう定義になる
// type OptionalItem = {
//     name?: string | undefined;
//     price?: number | undefined;
// };

なかなか面白い機能で、実装はこんな風になってるみたいですね。

type Partial<T> = {
    [P in keyof T]?: T[P];
};

他にもいろいろあるみたいですし、自分でユーティリティ型を作ってみるのも楽しそうです。

で、どっちを使うの?

サバイバルTypeScriptでは特に明確な正解はないと書かれています。
さらにそこからリンクされているGoogleのスタイルガイドでは、オブジェクト型の場合にはinterfaceを使うといいとのことです。
ということは、今回のオブジェクト型の話は基本的にはinterfaceが良さそうですね。
まぁ参画するプロジェクトのルール優先という感じにはなると思いますが、特にないならってくらいだと思いますが。

逆に言えばinterfaceでできなそうなことにtypeを使うのが良さそうです。
ユニオン型とかリテラル型とかを便利に使える場面はありそうですね。
関数型もFunctionaInterface的なことをすればinterfaceでも使えそうですが、これもtypeの方が見やすそうではある…?

そんなわけでちょっとだけ型に詳しくなったような気がします。