Code TypeScript

【TypeScript】 typeとinterfaceの違いと使い分け

TypeScriptには、型定義で使える構文としてinterfacetypeがあります。
この記事ではその違いについて整理します。

interfaceとは

interfaceは、クラスが実装するべきプロパティやメソッドを定義したものです。
JavaScriptにはinterface構文はありませんが、TypeScriptで実装されました。

classへの実装

interfaceの一般的な使い方は、class定義に実装して使用するというものです。
TypeScriptだけではなく、PHPやJavaなどの言語でも同様に実装されています。

interface AnimalInterface {
    name: string
    age: number
    greet: () => void
}

class Animal implements AnimalInterafce {
    constructor(name: string, age: number) {
        this.name = name
        this.age = age
    }

    greet: () => {
        console.log(`My name is ${this.name}. I'm ${this.age} years old!`
    }
}

const cat = new Animal('Max', 5)
cat.walk() // My name is Max. I’m 5 years old!

クラスで定義されるべきプロパティやメソッドとその型を定義し、クラスにそれらが実装されていることを保証することができます。

型注釈

TypeScriptでは、これとは別に型定義に名前をつけるために使用することができます。

interface AnimalInterface {
    name: string
    age: number
    greet: (name: string, age: number) => void
}

const cat: AnimalInterface = {
    name: 'Max',
    age: 5,
    greet: (name: string, age: number) => {
        console.log(`My name is ${name}. I'm ${age} years old!`),
    }
}

cat.greet(animal.name, animal.age)

ここでは、catオブジェクトがAnimalIntefaceの型定義を持つことを明示しています。
型注釈に合わないプロパティを持つオブジェクトを定義しようとするとエラーが出力されます。

const cat: AnimalInterface = {
    name: 'Max'
    age: 5
}
// Property 'greet' is missing in type '{ name: string; age: number; }' but required in type 'AnimalInterface'.ts(2741)

typeとは

typeは型エイリアスとも呼ばれ、型定義に別名を付与することができます。

type AnimalTYpe = {
    name: string
    age: number
    greet: (name: string, age: number) => void
}

interfaceとtypeの違いと使い分け

使用できる型の種類

プリミティブから交差型やインデックス型まで、基本的な型定義は両者ともに使用可能です。

interface TestInterface {
    name: string
    age: number
    isDog: boolean
    Parents: string[]
    youngs: string[] | undefined
    index: {
        [K: string]: string
    }
    intersectionObj: { hoge: string } & { fuga: string }
}
type TestType = {
    name: string
    age: number
    isDog: boolean
    Parents: string[]
    youngs: string[] | undefined
    index: {
        [K: string]: string
    }
    intersectionObj: { hoge: string } & { fuga: string }
}

型定義の拡張性

interface記法では、再宣言することで型定義が上書きではなく結合されます。
下の例では、Person型はnameプロパティとageプロパティを両方持つ型定義になります。

interface Person {
    name: string
}

interface Person {
    age: number
}

const Bob: Person = {
    name: 'Bob',
    age: 25
}
// Person型はnameとageプロパティを持つ

type記法では、このやり方での型定義拡張はできません。
Person型が重複していると怒られます。

type Person = {
    name: string
}

type Person = Person & {
    name: string
    age: number
}
// Duplicate identifier 'Person'

まとめ

ここまででinterfaceとtypeの違いについて整理しました。

問題は両者を実務でどのように使い分けるかですが、結論どちらを使っても大きな違いはありません。
個人的には特に理由がなければ、interfaceは拡張性が高くて使いやすいように見えますが、それが却って意図しない拡張をしてしまいバグを生んでしまいそうなためtypeで記述することをおすすめします。

-Code, TypeScript

© 2024 トンボのようにまっすぐ進んでいたい Powered by AFFINGER5