Skip to content

TypeScript インターフェイス

インターフェイスと呼び出しシグニチャ

ts
// 関数型による定義
type CalcFunction = (n1: number, n2: number) => number

// インターフェイスによる定義
type CalcInterface = (n1: number, n2: number) => number

const add: CalcFunction = (n1, n2) => n1 + n2
const subtract: CalcInterface = (n1, n2) => n1 - n2

インターフェイスの拡張

ts
// インターフェイスの拡張
interface Vehicle {
  speed: number
}

interface Car extends Vehicle {
  engineType: string
  volume: number
}

const superCar: Car = {
  speed: 240,
  engineType: 'V8',
  volume: 4000,
}

// プロパティのオーバーライド
interface Vehicle {
  speed: number
  model: string | null
}

// const sportsCar: Car = {
//   engineType: 'V4',
//   volume: 3000,
//   // 型 '{ engineType: string; volume: number; }' には 型 'Car' からの次のプロパティがありません: speed, modelts(2739)
// }

 上記の例では、Vehicleインターフェイスがベースインターフェイスとして機能し、Carインターフェイスは、Vehicleの全プロパティに加えて、新たなプロパティを持つことができるようになる。CarインターフェイスにはVehicleから継承したプロパティが含まれるため、Carインターフェイスを満たすオブジェクトを定義する際には、これらのプロパティを全て含める必要がある。

 変数sportsCarに代入しようとしているオブジェクトはspeedプロパティを持たないため、TypeScriptコンパイラはエラーを報告する。

プロパティのオーバーライド

ts
interface Vehicle {
  speed: number
  model: string | null
}

interface Car extends Vehicle {
  engineType: string
  model: string // modelプロパティをオーバーライド
}

 上記の例では、派生インターフェイスでmodelプロパティの型を、string|nullからstring型にオーバーライドしている。ただし、インターフェイスのプロパティをオーバーアライドする際には、派生インターフェイスのプロパティ型がベースインタフェイスのプロパティ型と互換性を有する必要がある。

複数のインターフェイスの拡張

ts
interface Born {
  birthYear: number
  place: string
}

interface Hobby {
  hobbies: string[]
}

interface Person extends Born, Hobby {
  name: string
}

const mike: Person = {
  name: 'Mike',
  birthYear: 1995,
  place: 'New York',
  hobbies: ['tennis', 'cooking', 'chess'],
}

 この機能を利用することで、すでに定義されている型を組み合わせて、より複雑な型を構築することが可能になり、コードの再利用性も向上する。

インターフェイスのマージ

ts
interface Car {
  engineType: string
  volume: number
}

interface Car {
  color: string
}

// OK. 過剰プロパティチェックが働くがエラーにならない。Carインターフェイスがマージされていることがわかる
const myCar: Car = {
  engineType: 'V8',
  volume: 4000,
  color: 'red',
}

// NG. colorプロパティが欠けているためエラーになる。Carインターフェイスがマージされていることがわかる
// const herCar: Car = {
//   engineType: 'V4',
//   volume: 3000,
// }
// プロパティ 'color' は型 '{ engineType: string; volume: number; }' にありませんが、型 'Car' では必須です。

 ただし、この機能の利用には注意が必要。インターフェイスの定義がプログラム全体に散らばってしまうと、個々の定義がどのように統合されて全体となるのかを理解するのが難しくなる。さらに、意図せずにインターフェイスがマージされてしまい、予期せぬ振る舞いやバグの原因となることもある。