TypeScriptを使っていると、ふとしたタイミングでコードの中に never という型が出てくることがあります。

never型って何?どこで使うものなの?
コードにneverが出てきたけど、なんでそこがnever型になってるのかわからない…
void型と何が違うの?どっちも「値を返さない」感じがして混乱する

この記事では、never型がどういう型なのか・どこに自然に現れるのか・意図的にどう活用するのかを、順番に説明していきます。

この記事は次のような方におすすめです。

この記事はこんな人におすすめ!
  • TypeScriptを学んでいて、never型が気になりだした方
  • コードの中でneverが出てきたが、何を意味するのかわからない方
  • void型とnever型の違いをはっきりさせたい方
  • ユニオン型の網羅性チェックについて知りたい方

この記事を読むと、never型の概念・実際に現れる場面・意図的に使うパターンが理解できます。型エラーのメッセージが読みやすくなる第一歩にもなるはずです。

それでは、順を追って詳しく見ていきましょう!

never型とは — 「絶対に値が返らない」を表す型

never型は、「値が存在しない」「絶対にそこには到達しない」ことを表す型です。

stringnumberのように「何らかの値を持つ型」とは全く別物で、never型の変数には文字通り「何も入らない」のです。

具体的にどういうときに使うかというと、「その場所に到達したら、プログラムが正常に動くはずがない」という文脈で登場します。たとえば必ず例外を投げる関数や、絶対に終わらない無限ループ関数の戻り値の型がneverになります。

「値が存在しない型」というのは、集合でいうと「空集合」に近いイメージです。要素が一つもない集合、つまりどんな値も属さない型——それがneverです。

neverの2つの特性を理解する

neverには、直感に少し反する2つの特性があります。これを先に押さえておくと、後の話がスムーズに理解できます。

① never型の変数には、何も代入できない

let value: never;

value = 1;       // エラー:Type 'number' is not assignable to type 'never'
value = "hello"; // エラー
value = null;    // エラー

never型の変数には、stringでもnumberでもnullでも、何も入れることができません。「値が存在しない型」なので、何かを代入しようとするとTypeScriptが即座にエラーを出します。

② never型の値は、どんな型の変数にも代入できる

逆に、never型の値はstring型やnumber型の変数にも代入できます。

function fail(message: string): never {
  throw new Error(message);
}

const s: string = fail("エラー"); // 型エラーにならない
const n: number = fail("エラー"); // 型エラーにならない

「それっておかしくない?」と感じるかもしれませんが、考えると筋が通っています。fail()は必ず例外を投げるので、実際にはsnに値が入ることは絶対にありません。「到達しない場所での代入」は、どんな型に対しても問題ない——そういう扱いになっています。

なかむぅ
なかむぅ
この②の特性は、後で紹介する「網羅性チェック」の仕組みを支えています。

never型はどこに現れるのか

never型を意図的に使う前に、まず「気づかずにneverが出てくるケース」を知っておきましょう。コードを読んでいてneverが現れたときに、何が起きているのかが読めるようになります。

必ず例外を投げる関数

関数の中にthrowだけがあって、正常な戻り値を返さない場合、TypeScriptはその関数の戻り値の型をneverと推論します。

function throwError(message: string): never {
  throw new Error(message);
  // この関数は絶対に値を返さない
}

この関数は必ず例外を投げて終わるため、呼び出し元に値が返ってくることは「絶対にない」。だから戻り値の型はneverです。

無限ループ関数

終わりのない無限ループを持つ関数も、同じ理由で戻り値がneverになります。

function infiniteLoop(): never {
  while (true) {
    // 永遠に繰り返す処理
  }
}

「正常に終わって値を返す」ことが絶対にないので、戻り値の型はneverです。

型の絞り込みで消えたとき

もう少し高度なケースですが、知っておくと役立ちます。

ユニオン型を型ガードで絞り込んでいくと、最終的にすべての型の可能性がなくなった時点で、その箇所の型がneverになります。

type Shape = "circle" | "square";

function describe(shape: Shape): string {
  if (shape === "circle") {
    return "丸";   // ここのshapeは "circle"
  }
  if (shape === "square") {
    return "四角"; // ここのshapeは "square"
  }
  // ここではすべての可能性が消えた → shapeはnever型
  // 実際には絶対に到達しない
  const _check: never = shape;
  throw new Error("想定外の値");
}

この「絞り込んで消えた型がnever」という性質が、次に紹介する網羅性チェックの核心です。

なかむぅ
なかむぅ
ユニオン型と型ガードについて詳しく知りたい場合は、こちらの記事を参照してください。
TypeScriptのユニオン(Union)型とは?型ガードで「どの型か」を安全に絞り込む方法
TypeScriptのユニオン(Union)型とは?型ガードで「どの型か」を安全に絞り込む方法TypeScriptのユニオン型とは何かを基礎から解説。typeof・in・instanceofを使った型ガードの違いと使い分けも初心者向けにわかりやすく整理します。...

never型を意図的に使う — ユニオン型の網羅性チェック

ここからが、never型を積極的に活用する場面です。

ユニオン型に対してswitch文で各ケースを処理するパターンはよく出てきます。このときneverを組み合わせると、「ケースの処理漏れを型エラーとして検出できる」という仕組みが作れます。

switch文とneverの組み合わせ方

次のコードを見てください。

type Shape = "circle" | "square" | "triangle";

function getArea(shape: Shape): number {
  switch (shape) {
    case "circle":
      return 3.14;
    case "square":
      return 1;
    default:
      // ここに到達する = 処理が漏れているケースがある
      const _exhaustiveCheck: never = shape; // 型エラーが出る!
      throw new Error(`未対応の形: ${_exhaustiveCheck}`);
  }
}

このコードは"triangle"のケースが抜けています。するとdefault節に"triangle"が流れ込んできます。このときshapeの型は"triangle"なので、never型の変数_exhaustiveCheckに代入しようとするとTypeScriptが型エラーを出してくれます

これが「網羅性チェック(exhaustive check)」と呼ばれるパターンです。_exhaustiveCheckという変数名は慣例的によく使われます(名前はなんでもOKです)。

ケースを追加したときに型エラーで気づける効果

このパターンの本当のメリットは、後から型を追加したときに、処理の追加漏れをエラーで即座に気づけることです。

たとえば後からShape"pentagon"を追加したとします。

// "pentagon"を追加
type Shape = "circle" | "square" | "triangle" | "pentagon";

function getArea(shape: Shape): number {
  switch (shape) {
    case "circle":
      return 3.14;
    case "square":
      return 1;
    case "triangle":
      return 0.5;
    default:
      // "pentagon"がここに流れ込む → neverへの代入で型エラー!
      const _exhaustiveCheck: never = shape;
      throw new Error(`未対応の形: ${_exhaustiveCheck}`);
  }
}

getArea関数に"pentagon"のcaseを追加し忘れていると、TypeScriptが型エラーで教えてくれます

網羅性チェックがない場合、「pentagonが渡されたときに想定外の動作をする」というバグが実行時まで気づかれないことがあります。neverを使うことで、そのリスクをコンパイル時に防げます。

void型との違いを整理する

never型を学ぶと、「void型と何が違うの?」という疑問が出てきます。どちらも「関数が値を返さない」文脈で登場するため、混乱しやすいポイントです。

一言で言うと、voidは「返す値がないが、関数は正常に終わる」、neverは「関数が絶対に終わらない」という違いがあります。

void never
意味 返す値がない(undefinedを返す) 絶対に値を返さない・到達しない
使う場面 副作用のみの関数(console.logなど) 例外を投げる関数・無限ループ
正常終了 する しない
// void: 正常に終わるが、返す値がない
function log(message: string): void {
  console.log(message);
  // undefinedが暗黙的に返る
}

// never: 正常には終わらない
function fail(message: string): never {
  throw new Error(message);
  // ここに到達することはない
}

「返す値がないだけで、関数自体は終わる」ならvoid。「そもそも関数が正常には終わらない」ならneverと覚えておきましょう。

【付録】さらに学びを深めるためのリソース


さらにTypescriptの学習を進めたい方のために、いくつかのリソースを紹介します。
これらのリソースを活用することで、TypeScriptの型システムについてより深い知識を得ることができるでしょう。

おすすめの書籍

ゼロからわかる TypeScript入門


技術評論社から出版されている「ゼロからわかる TypeScript入門」は、プログラミング初心者や本職プログラマーではない方を主な対象にした入門書です。

変数・条件分岐・ループといった基本から、クラスやインターフェース、モジュールまで段階的に学べる構成になっています。最終章ではWeb APIとJSONを使った非同期Webアプリの作成も体験できるので、「実際に動くものを作る」ところまで到達できます。

プロを目指す人のためのTypeScript入門


技術評論社の「プロを目指す人のためのTypeScript入門 安全なコードの書き方から高度な型の使い方まで」、通称 ブルーベリー本 です。
JavaScriptの仕様とTypeScript独自の機能を両方押さえつつ、リテラル型・ユニオン型・keyof型・ジェネリクスなど、高度な型表現まで踏み込んで解説しています。TypeScriptの型システムの表現力を本格的に学べる一冊です。

オンラインで参照できる公式ドキュメント

TypeScript公式ハンドブック


https://www.typescriptlang.org/docs/
TypeScriptの公式ドキュメントです。
intersection型を含む、すべての型システムの機能について詳細な説明があります。

TypeScript Deep Dive


https://basarat.gitbook.io/typescript/
TypeScriptの深い部分まで掘り下げて解説しているオンラインブックです。
無料で読むことができ、intersection型についても詳しく説明されています。

TypeScriptの学習は終わりがありません。
新しい機能が常に追加され、より良い書き方が発見されています。
継続的に学習を続けることで、より良いTypeScriptプログラマーになれるはずです。


まとめ — never型を知ると「型エラーの意味」が見えてくる

この記事で扱ったことを振り返ります。

  • never型は「値が存在しない・絶対に到達しない」を表す型
  • neverの2つの特性:何も代入できない/逆に何にでも代入できる
  • 自然にneverが現れる場面:例外を投げる関数・無限ループ・型の絞り込みで消えたとき
  • 意図的な使いどころ:ユニオン型のswitch文と組み合わせた網羅性チェック
  • void型との違い:voidは正常終了する・neverはしない

never型は最初「なぜ必要?」と感じる型ですが、網羅性チェックのパターンを一度使うと、「型システムがバグを防いでくれている」という感覚が実感できると思います。コードが増えてきたときほど、この仕組みのありがたさがわかってきます。

※本記事の本文案はAIを活用して作成していますが、記載している内容およびコードは筆者が実際に調査、検証・実行し、内容の正確性を確認した上で公開しています。