項目59 never型を使って網羅性チェックを行う
Switch文などで、ある型が取りうるすべての値が処理されていることを保証することをを網羅性チェックという 網羅性チェックはnever型の変数に値を代入できないことを利用して行う
never型の変数を用意して、網羅的ていないパターンの値が代入されたらエラーとして網羅的チェックを行う
TypeScript上では、パターンを網羅できていない場合は型エラーが発生するが、JavaScirptとしては実行できるため、実行時の想定外の値からも守るために例外を投げるようにしている
code:ts
interface Box {type: 'box'; topLeft: Coord; size: Coord;}
interface Circle {type: 'circle'; center: Coord; radius: number;}
interface Line {type: 'line'; start: Coord; end: Coord;}
type Shape = Box | Circle | Line;
function processShape(shape: Shape) {
switch (shape.type) {
case 'box': break;
case 'circle': break;
default:
const exhaustiveCheck: never = shape;
// ~~~~~~~~~~~~~~~ Type 'Line' is not assignable to type 'never'.
// 型 'Line' を型 'never' に割り当てることはできません。
throw new Error(Missed a case: ${exhaustiveCheck});
}
}
satisfiesを使った網羅性チェック
code:ts
function processShape(shape: Shape) {
switch (shape.type) {
case 'box': break;
case 'circle': break;
default:
shape satisfies never
// ~~~~~~~~~ Type 'Line' does not satisfy the expected type 'never'.
// 型 'Line' は想定された型 'never' を満たしていません。
throw new Error(Missed a case: ${shape});
}
}
複数の分岐からreturnする関数には、戻り値の型アノテーションをつける。ただし、それでも明示的な網羅性チェックは必要 網羅性チェックが行われていない場合、特定の型もしくはundefinedが返されるため、戻り値の型アノテーションをつけることで型安全性を向上させる
code:ts
function getArea(shape: Shape): number {
// ~~~~~~ Function lacks ending return statement and
// return type does not include 'undefined'.
// 関数に終了の return ステートメントがなく、
// 戻り値の型に 'undefined' が含まれません。
switch (shape.type) {
case 'box':
return width * height;
case 'circle':
return Math.PI * shape.radius ** 2;
}
}
code:ts
type Play = 'rock' | 'paper' | 'scissors';
function shoot(a: Play, b: Play) {
const pair = ${a},${b} as ${Play},${Play}; // or: as const
// ^? const pair: "rock,rock" | "rock,paper" | "rock,scissors" |
// "paper,rock" | "paper,paper" | "paper,scissors" |
// "scissors,rock" | "scissors,paper" | "scissors,scissors"
switch (pair) {
case 'rock,rock':
case 'paper,paper':
// ~~~~~~~~ 省略 ~~~~~~~~
default:
assertUnreachable(pair);
// ~~~~ Argument of type 'string' is not
// assignable to parameter of type 'never'.
// 型 'string' の引数を型 'never' の
// パラメーターに割り当てることはできません。
// ^? const pair: "scissors,paper"
}
}