TypeScriptのneverキーワード: 完全なガイド

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型の特性をいくつか紹介します。

  1. 他の型に割り当てられない: never型の値は、他のどの型にも割り当てることができません。これは、never型の値が存在しないからです。つまり、never型の値を生成することはできません。
let x: never;
let y: number;

// Error: Type 'never' is not assignable to type 'number'.
y = x;
  1. 他の型を割り当てることができる: 一方、他のどの型もnever型に割り当てることができます。しかし、これは理論的な話で、実際にはnever型の値を得ることはできません。
let x: never;
let y: number = 4;

// No Error
x = y;
  1. 網羅性チェックに使用される: never型は、TypeScriptの網羅性チェックにおいて重要な役割を果たします。これにより、すべてのケースが適切に処理されていることを確認することができます。

以上が、TypeScriptのnever型の主な特性です。次のセクションでは、これらの特性を活用した具体的な使用例について説明します。

never型の使用例

TypeScriptのnever型は、主に以下のような場合に使用されます。

  1. エラーをスローする関数: never型は、エラーをスローする関数の戻り値の型として使用されます。以下に例を示します。
function throwError(message: string): never {
  throw new Error(message);
}

この関数は、呼び出されると必ずエラーをスローします。そのため、戻り値の型としてneverを指定します。

  1. 絶対に終了しない関数: never型は、絶対に終了しない関数(例えば、無限ループする関数)の戻り値の型としても使用されます。
function infiniteLoop(): never {
  while (true) {}
}

この関数は、無限ループするため、終了しません。そのため、戻り値の型としてneverを指定します。

  1. 網羅性チェック: 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型という二つの特殊な型が存在します。これらは似ているように見えますが、それぞれ異なる目的と使用法を持っています。

  1. void型: void型は、値を返さない関数の戻り値の型として使用されます。つまり、void型の関数は、値を返すことなく終了します。
function log(message: string): void {
  console.log(message);
}

この関数は、メッセージをログに出力するだけで、何も返しません。そのため、戻り値の型としてvoidを指定します。

  1. 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;の行でエラーを報告します。これは、valuenever型であるべき場所(すなわち、すべてのケースが網羅されている場所)で'qux'という値を持つことができるからです。

このように、never型は網羅性チェックにおいて非常に有用なツールとなります。

コメントする