TypeScriptには、型定義で使える構文としてinterfaceとtypeがあります。
この記事ではその違いについて整理します。
Contents
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で記述することをおすすめします。