never型の基本
TypeScriptのnever
型は、他のどの型にも割り当てられない値を表します。つまり、never
型の変数は他の値を持つことができません。
以下に、never
型を返す関数の例を示します。
function error(message: string): never {
throw new Error(message);
}
この関数はエラーをスローするため、正常に終了することはありません。そのため、戻り値の型としてnever
を使用します。このように、never
型は通常、エラーをスローする関数や絶対に終了しない関数(無限ループする関数など)の戻り値の型として使用されます。
また、never
型は、TypeScriptの型システムの中で「最下位」に位置します。つまり、他のどの型もnever
型に割り当てることはできませんが、never
型の値は他のどの型にも割り当てることができます。しかし、実際にはnever
型の値を得ることはできないため、この特性はあまり役に立ちません。
以上が、TypeScriptのnever
型の基本的な特性と使用方法です。次のセクションでは、never
型の詳細な特性と使用例について説明します。
never型の特性
TypeScriptのnever
型は、その名前が示す通り、決して何も返さないことを表します。これは、関数が例外をスローするか、絶対に終了しない(例えば、無限ループになる)場合に使用されます。
以下に、never
型の特性をいくつか紹介します。
- 他の型に割り当てられない:
never
型の値は、他のどの型にも割り当てることができません。これは、never
型の値が存在しないからです。つまり、never
型の値を生成することはできません。
let x: never;
let y: number;
// Error: Type 'never' is not assignable to type 'number'.
y = x;
- 他の型を割り当てることができる: 一方、他のどの型も
never
型に割り当てることができます。しかし、これは理論的な話で、実際にはnever
型の値を得ることはできません。
let x: never;
let y: number = 4;
// No Error
x = y;
- 網羅性チェックに使用される:
never
型は、TypeScriptの網羅性チェックにおいて重要な役割を果たします。これにより、すべてのケースが適切に処理されていることを確認することができます。
以上が、TypeScriptのnever
型の主な特性です。次のセクションでは、これらの特性を活用した具体的な使用例について説明します。
never型の使用例
TypeScriptのnever
型は、主に以下のような場合に使用されます。
- エラーをスローする関数:
never
型は、エラーをスローする関数の戻り値の型として使用されます。以下に例を示します。
function throwError(message: string): never {
throw new Error(message);
}
この関数は、呼び出されると必ずエラーをスローします。そのため、戻り値の型としてnever
を指定します。
- 絶対に終了しない関数:
never
型は、絶対に終了しない関数(例えば、無限ループする関数)の戻り値の型としても使用されます。
function infiniteLoop(): never {
while (true) {}
}
この関数は、無限ループするため、終了しません。そのため、戻り値の型としてnever
を指定します。
- 網羅性チェック:
never
型は、TypeScriptの網羅性チェックにおいて重要な役割を果たします。これにより、すべてのケースが適切に処理されていることを確認することができます。
type Foo = 'foo';
function check(value: Foo | never) {
if (value !== 'foo') {
const unreachable: never = value;
}
}
以上が、TypeScriptのnever
型の主な使用例です。次のセクションでは、void
型とnever
型の違いについて説明します。
void型とnever型の違い
TypeScriptには、void
型とnever
型という二つの特殊な型が存在します。これらは似ているように見えますが、それぞれ異なる目的と使用法を持っています。
- void型:
void
型は、値を返さない関数の戻り値の型として使用されます。つまり、void
型の関数は、値を返すことなく終了します。
function log(message: string): void {
console.log(message);
}
この関数は、メッセージをログに出力するだけで、何も返しません。そのため、戻り値の型としてvoid
を指定します。
- never型: 一方、
never
型は、決して何も返さないことを表します。これは、関数が例外をスローするか、絶対に終了しない(例えば、無限ループになる)場合に使用されます。
function throwError(message: string): never {
throw new Error(message);
}
この関数は、呼び出されると必ずエラーをスローします。そのため、戻り値の型としてnever
を指定します。
以上が、void
型とnever
型の主な違いです。次のセクションでは、網羅性チェックに応用するnever
型について説明します。
網羅性チェックに応用するnever型
TypeScriptのnever
型は、網羅性チェックにおいて重要な役割を果たします。これは、すべてのケースが適切に処理されていることを確認するためのものです。
例えば、限定的な値を持つ型(例えば、リテラル型)に対するswitch文を書く場合、すべての可能なケースを網羅しているかどうかを確認するためにnever
型を使用することができます。
以下に、その例を示します。
type Foo = 'foo' | 'bar' | 'baz';
function doSomething(value: Foo) {
switch (value) {
case 'foo':
return doFoo();
case 'bar':
return doBar();
case 'baz':
return doBaz();
default:
const check: never = value;
return check;
}
}
この関数では、value
の型がFoo
であり、Foo
は'foo'
、'bar'
、'baz'
のいずれかの値を持つことができます。switch文では、これらのすべてのケースを網羅しています。
もし新たに'qux'
という値をFoo
に追加した場合、TypeScriptの型チェッカーはcheck: never = value;
の行でエラーを報告します。これは、value
がnever
型であるべき場所(すなわち、すべてのケースが網羅されている場所)で'qux'
という値を持つことができるからです。
このように、never
型は網羅性チェックにおいて非常に有用なツールとなります。