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'; } }
型が変更された際のコードの更新
新しい値がユニオン型に追加された場合、エラーが発生します。例えば、SupportedColour2
にGREEN
を追加すると、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); } }
ensureExhaustive
はnever
型を受け取るため、型が漏れている場合には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コードを書くことができます。