にょっす速報🐮✋

TypeScriptでの厳密な分岐チェックを実現する方法【Next.js AppRouter対応】

この記事の目次

TypeScriptで開発を行う際、列挙型(enum)やユニオン型のように、特定の値のリストを持つ型を使うことがよくあります。例えば以下のような例です。

enum SupportedColour1 {
  RED,
  YELLOW,
  BLUE,
}

type SupportedColour2 = 'RED' | 'YELLOW' | 'BLUE';

このような型を使うと、関数の引数としてそれらの値を受け取り、値によって異なる動作をさせたり、異なる値を返したりすることが可能です。

function codeForColour1(colour: SupportedColour1): string {
  switch (colour) {
    case SupportedColour1.BLUE:
      return '#0000ff';
    case SupportedColour1.RED:
      return '#ff0000';
    case SupportedColour1.YELLOW:
      return '#ffff00';
  }
}

function codeForColour2(colour: SupportedColour2): string {
  switch (colour) {
    case 'BLUE':
      return '#0000ff';
    case 'RED':
      return '#ff0000';
    case 'YELLOW':
      return '#ffff00';
  }
}

型が変更された際のコードの更新

新しい値がユニオン型に追加された場合、エラーが発生します。例えば、SupportedColour2GREENを追加すると、TypeScriptは関数内でGREENに対応する処理がないことを検出し、エラーを表示します。

type SupportedColour2 = 'RED' | 'YELLOW' | 'BLUE' | 'GREEN';

function codeForColour2(colour: SupportedColour2): string {
  switch (colour) {
    case 'BLUE':
      return '#0000ff';
    case 'RED':
      return '#ff0000';
    case 'YELLOW':
      return '#ffff00';
  }
}

エラーメッセージ:

Function lacks ending return statement and return type does not include 'undefined'.

このエラーが発生する理由は、GREENが渡された場合に戻り値がないためです。TypeScriptがエラーを出さないケースもあり、例えば、以下のように関数が値を返さない場合です。

function logForColour(colour: SupportedColour2): void {
  switch (colour) {
    case 'BLUE':
      console.log('User picked blue');
    case 'RED':
      console.log('User picked red');
    case 'YELLOW':
      console.log('User picked yellow');
  }
}

この場合、GREENの分岐がなくてもエラーが出ないため、意図せずにケースが漏れてしまう可能性があります。

ensureExhaustiveヘルパーの導入

このような漏れを防ぎ、エラーをより明確にするために、ensureExhaustiveというヘルパー関数を用意しておくと便利です。

export function ensureExhaustive(_x: never): never {
  throw new Error('Reached a branch with non-exhaustive checks');
}

この関数を使うことで、分岐内にデフォルトケースを追加し、すべてのケースがカバーされていることを確認できます。

function logForColour(colour: SupportedColour2): void {
  switch (colour) {
    case 'BLUE':
      console.log('User picked blue');
      break;
    case 'RED':
      console.log('User picked red');
      break;
    case 'YELLOW':
      console.log('User picked yellow');
      break;
    default:
      ensureExhaustive(colour);
  }
}

ensureExhaustivenever型を受け取るため、型が漏れている場合にはTypeScriptがエラーを検出してくれます。

// エラーメッセージ例:
Argument of type 'string' is not assignable to parameter of type 'never'.(2345)
(parameter) colour: "GREEN"

TypeScriptは、関数に不足している値がある場合、それを正確に指摘してくれます。

ifやelse文にも対応可能

このensureExhaustiveは、switch文だけでなく、ifやelse文など、TypeScriptが型の絞り込みを適用する他の状況でも有効です。

常に厳密なチェックを心がけよう

この方法を活用することで、コード内のすべてのケースがカバーされていることを確認でき、値が追加されるたびにコードの更新が必要な箇所が明示的にわかるようになります。TypeScriptでの厳密な分岐チェックを実現し、堅牢なコードを作成するために、ensureExhaustiveを導入する習慣をつけましょう。

この方法で、漏れのない型チェックが実現しやすくなり、堅牢で保守性の高いTypeScriptコードを書くことができます。

);

コメント(0件)


トピックス