Skip to content

TypeScript interfaceの使い方:型定義の基本

はじめに

TypeScriptで開発を進めていると、同じオブジェクト構造を複数の場所で使いたい場面に出会います。そのたびにオブジェクト型を直接書いていては、コードの見通しが悪くなり、修正も煩雑になります。

こうした課題を解決するのが、interfaceによる名前付き型定義です。本記事では、interfaceの基本的な宣言方法から、型チェックの仕組み、余剰プロパティチェックの動作、そして型の再利用による保守性の向上までを、コード例を交えて解説します。

TypeScriptの型アノテーションを学び始めた方が、interfaceを正しく使いこなすための基礎を身につけられる内容になっています。

型アノテーションやオブジェクト型の基本については、以下の記事で解説しています。

https://scriptlab.jp/typescript-types-and-setup-guide/ scriptlab.jp

interfaceによるオブジェクト型の宣言

TypeScriptでは、変数に型アノテーションとしてオブジェクトの構造を直接記述できます。たとえば、名前と年齢を持つオブジェクトは次のように書きます。


const person: {
  name: string
  age: number
} = {
  name: 'Michael Jackson',
  age: 28,
}

この書き方は「無名のオブジェクト型」と呼ばれます。型に名前がないため、同じ構造を別の場所で使いたいときに毎回書き直す必要があります。

interfaceを使うと、この型に名前を付けて宣言できます。


interface Person {
  name: string
  age: number
}

const person: Person = {
  name: 'Michael Jackson',
  age: 28,
}

ここでは、namestring型、agenumber型であるオブジェクトの構造をPersonという名前で定義しています。一度定義したinterfaceは、型アノテーションとして繰り返し利用できます。

以下の図は、無名のオブジェクト型とinterfaceの関係を示しています。


flowchart LR
    A[オブジェクトの構造] --> B[無名のオブジェクト型]
    A --> C[interface]
    B --> D[その場限りの利用]
    C --> E[名前を付けて再利用]

このように、interfaceは型に名前を与え、再利用可能にするための仕組みです。

interfaceで利用できる修飾子

interfaceでは、通常のオブジェクト型と同様に、オプショナルを表す?readonlyの修飾子を利用できます。?を付けたプロパティは省略可能になり、readonlyを付けたプロパティは代入後の変更が禁止されます。

interfaceを用いた型チェックの動作

interfaceで宣言した型は、無名のオブジェクト型と同じ型チェックの仕組みが適用されます。interfaceに存在しないプロパティへアクセスしようとすると、コンパイルエラーになります。


interface Person {
  name: string
  age: number
}

const person: Person = {
  name: 'Michael Jackson',
  age: 28,
}

console.log(person.height) // エラー: Property 'height' does not exist on type 'Person'.

この例では、Personインターフェースにはheightプロパティが定義されていません。そのため、person.heightへのアクセスはコンパイル時にエラーとして検出されます。

型チェックにより、存在しないプロパティへの誤ったアクセスを実行前に防ぐことができます。これはTypeScriptの型システムが提供する安全性の基本的な仕組みです。

余剰プロパティチェックの理解と注意点

interfaceを使ったコードで特に注意が必要なのが、余剰プロパティチェックと呼ばれる仕組みです。これは、オブジェクトリテラルを直接代入する際に、interfaceに定義されていないプロパティが含まれているとエラーになる機能です。

オブジェクトリテラルの直接代入時の挙動

interfaceで定義した型を持つ変数に、オブジェクトリテラルを直接代入する場合を見てみます。


interface Person {
  name: string
  age: number
}

const person: Person = {
  name: 'Michael Jackson',
  age: 28,
  height: 175, // エラー: Object literal may only specify known properties.
}

heightはPersonインターフェースに定義されていません。オブジェクトリテラルを直接代入しているため、余剰プロパティチェックが働きエラーとなります。

変数を介した代入時の挙動

一方で、一度別の変数に格納してから代入する場合には、余剰プロパティチェックは行われません。


const data = {
  name: 'Michael Jackson',
  age: 28,
  height: 175,
}

const person: Person = data // エラーにならない

dataにはheightという余剰なプロパティが含まれていますが、変数を介した代入では余剰プロパティチェックが適用されないため、エラーになりません。

以下の図は、余剰プロパティチェックの判定フローを示しています。


flowchart TD
    A[オブジェクトの代入] --> B{オブジェクトリテラルの直接代入か}
    B -->|はい| C{interfaceに未定義のプロパティがあるか}
    B -->|いいえ| D[余剰プロパティチェックなし]
    C -->|はい| E[コンパイルエラー]
    C -->|いいえ| F[代入成功]
    D --> F

この図のように、余剰プロパティチェックはオブジェクトリテラルの直接代入時にのみ実行されます。変数を介した代入ではチェックが行われないため、意図しないプロパティが混入する可能性がある点に注意が必要です。

interfaceによる型の再利用と保守性の向上

interfaceの大きな利点は、同じ型定義を複数の場所で再利用できることです。変数の型アノテーションだけでなく、関数のパラメータや戻り値の型としても活用できます。


interface Person {
  name: string
  age: number
}

const person: Person = {
  name: 'Michael Jackson',
  age: 28,
}

function greet(person: Person): string {
  return `Hello, ${person.name}!`
}

console.log(greet(person))

この例では、Personインターフェースを変数personの型と関数greetのパラメータの型の両方で使っています。型定義が一箇所にまとまっているため、プロパティの追加や変更があった場合にも、interfaceの定義を修正するだけで済みます。

interfaceを活用することで、コード全体で一貫した型チェックが行われ、保守性の高い設計が実現できます。TypeScript公式ドキュメントでも、オブジェクトの形状を定義する手段としてinterfaceの利用が推奨されています。

TypeScript公式ハンドブック – Object Types

Documentation - Object Types www.typescriptlang.org

終わりに

本記事では、TypeScriptのinterfaceについて、基本的な宣言方法から型チェックの仕組み、余剰プロパティチェック、そして型の再利用まで解説しました。interfaceは型に名前を付けて管理するための基本的な機能であり、コードの可読性と保守性を大きく向上させます。

interfaceを使いこなすことで、プロジェクト全体で一貫した型定義を維持できるようになります。まずは本記事のコード例を実際に試しながら、interface宣言と余剰プロパティチェックの挙動を確認してみてください。

TypeScriptの型システムを正しく理解することが、安全で保守性の高いコードへの第一歩です。

interfaceと合わせて理解しておきたい型推論の仕組みについては、以下の記事で解説しています。

https://scriptlab.jp/typescript-type-inference-widening-guide/ scriptlab.jp

コメントを残す