【TypeScript】unknown型とnever型 - 実践的な使用法
2024-10-25
2024-10-25
TypeScript
のunknown
型とnever
型は、他の言語にはあまり見られないユニークな型であり、型安全性を向上させ、予期しない動作を防ぐために非常に役立ちます。本記事では、unknown
型とnever
型の違いや、それぞれの実践的な使用方法について解説し、より堅牢なTypeScript
コードを実現するための手法を紹介します。
unknown型とは?
unknown
型は、「どんな値でも受け取れるが、その値を使用する前に必ず型チェックをしなければならない型」です。unknown
は、any
型に似ていますが、値を扱う際に安全な型チェックが必要である点で異なります。
unknown型の基本的な使い方
例えば、APIレスポンスやユーザーからの入力のように、型が事前にわからないデータを処理する場合にunknown
型を使用します。
let input: unknown;
input = "Hello"; // OK
input = 42; // OK
input = true; // OK
このように、unknown
型はどんな型の値でも代入可能です。しかし、unknown
型の値をそのまま使用しようとするとエラーが発生します。値を安全に操作するためには、事前に型チェックを行う必要があります。
let input: unknown;
input = "Hello";
console.log(input.length); // エラー: 'input'は'unknown'型なのでプロパティにアクセスできません
上記のコードでは、input
がunknown
型のため、直接length
プロパティにアクセスすることはできません。そこで、型チェックを行ってから値を操作する必要があります。
型チェックとunknown型の安全な使用
unknown
型の値を使用する際には、typeof
やinstanceof
を使って型チェックを行います。これにより、予期しない型によるエラーを防ぎ、コードの安全性が向上します。
function printLength(input: unknown) {
if (typeof input === "string") {
console.log(input.length); // 型チェック後なのでOK
} else {
console.log("Not a string");
}
}
printLength("Hello"); // 5
printLength(42); // Not a string
このように、unknown
型は明確な型チェックを行うことで安全に使用でき、any
型と比較してより堅牢な型安全性を提供します。
APIレスポンスの例
unknown
型は、APIからの不確定なレスポンスを処理する際にも役立ちます。たとえば、外部APIのレスポンスデータを事前に予測できない場合、unknown
型を使い、取得後に型を判定して安全に処理を行います。
async function fetchData(): Promise<unknown> {
// APIからデータを取得
return await fetch("/api/data").then((res) => res.json());
}
async function processData() {
const data = await fetchData();
if (typeof data === "object" && data !== null && "userId" in data) {
console.log((data as { userId: number }).userId); // 型チェック後に型キャスト
} else {
console.log("Invalid data format");
}
}
processData();
この例では、APIレスポンスの型が不明であるため、unknown
型を使用し、レスポンスの内容に応じて安全に型キャストしています。
never型とは?
never
型は、「決して値を返さないことを示す型」であり、主に次のような場面で使用されます。
- 関数が例外を投げる
- 無限ループで終了しない
- 型推論で「絶対に発生しない」型を表す
never
型は、値が返らないことを明示的に示すことで、開発者に対して関数の振る舞いを正確に伝える役割を果たします。
never型の基本的な使い方
例えば、エラーを発生させてプログラムを強制終了させる関数には、never
型が使用されます。
function throwError(message: string): never {
throw new Error(message);
}
このthrowError
関数は常にエラーを投げるため、決して正常な値を返しません。そのため、戻り値の型としてnever
が適切です。
無限ループとnever型
また、無限ループを持つ関数も決して戻り値を返さないため、never
型を指定することができます。
function infiniteLoop(): never {
while (true) {
// 永遠に実行される
}
}
このように、never
型は関数が「正常に終了しない」ことを明示するため、コードの意図が分かりやすくなります。
型推論でのnever型
TypeScript
は型推論によって、switch
文などで発生し得ないケースに対してもnever
型を自動的に割り当てることがあります。これにより、意図しない型の処理ミスを防ぐことができます。
type Shape = "circle" | "square";
function getArea(shape: Shape) {
switch (shape) {
case "circle":
return Math.PI * 1 * 1;
case "square":
return 1 * 1;
default:
const _exhaustiveCheck: never = shape;
throw new Error(`Unknown shape: ${_exhaustiveCheck}`);
}
}
この例では、Shape
型に存在しない型がswitch
文に追加された場合、自動的にnever
型として推論され、エラーが発生するため、未処理のケースを防げます。
unknown型とnever型の違い
unknown
型とnever
型は、どちらもTypeScript
の型システムにおいて特定の役割を果たしますが、その目的と使用方法には明確な違いがあります。
- unknown型
不明な型で、型チェックが必要な型。任意の値を受け入れますが、使用前に型の確認が必要。 - never型
決して値を返さない型。関数が終了しないことや例外を投げることを明示します。 これらの型を適切に使い分けることで、コードの安全性と可読性が向上し、予期しないエラーを未然に防ぐことができます。
まとめ
TypeScript
におけるunknown
型とnever
型は、それぞれ特定の場面で非常に有効な型です。
unknown
型は、不明な型を安全に扱い、明確な型チェックを必要とする場合に使用され、never
型は、値を決して返さない関数や、発生し得ない型のチェックに役立ちます。
これらの型を正しく活用することで、コードの型安全性を高め、予期しないエラーを防止することができます。TypeScript
の型システムを活用して、より堅牢で保守性の高いコードを書いていきましょう。