TypeScriptを書いていると、nullとundefinedのどちらを使えばいいのか、どうやってエラーを防げばいいのか、意外と悩むことが多いですよね。

nullとundefinedって何が違うの?どっちを使えばいいの?
「Object is possibly ‘null’」というエラーが出たけど、どう直せばいい?
TypeScriptでnullの型ってどうやって書くの?普通の型と何が違うの?

この記事では、nullとundefinedが「TypeScriptの型」としてどう扱われるのか、安全にコードを書くための基本的なパターン、そして使い分けの考え方について順番に説明します。

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

この記事はこんな人におすすめ!
  • TypeScriptを学び始めたばかりで、nullとundefinedの扱いに迷っている方
  • 「Object is possibly ‘null’」や「possibly undefined」というエラーが出て困っている方
  • null/undefinedを型でどう表現するのか知りたい方
  • nullとundefinedのどちらを使えばいいか判断できるようになりたい方

この記事を読むと、TypeScriptにおけるnull/undefinedの型の書き方と、安全にチェックするための基本パターンが理解できます。「なぜエラーが出るのか」の仕組みも一緒にわかるので、エラーに遭遇したときに落ち着いて対処できるようになります。

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

nullとundefinedとは — TypeScriptにおける2つの「値なし」

nullとundefinedとは — TypeScriptにおける2つの「値なし」

TypeScriptの型システムでは、nullとundefinedはそれぞれ独立した型として扱われます。ざっくり言うと「両方とも値がない状態を表すが、意味合いが違う」という感じです。

nullは「意図的に空」、undefinedは「まだ値がない」

まず意味の違いを整理しておきましょう。

  • undefined
    変数が宣言されたが、まだ値が代入されていない状態。TypeScript(JavaScript)が自然に設定する「値がない」の表現です。
  • null
    図的に空である」ことを表すために、プログラマーが明示的に代入する値です。「値なし」を明確に伝えたいときに使います。
let name: string; // 宣言しただけ → undefinedになる
console.log(name); // undefined

let selected: string | null = null; // 意図的に「まだ選択されていない」を表現

undefinedは「そもそも値が設定されていない」nullは「値がないことをちゃんと表明している」というニュアンスです。

TypeScriptにおける型アノテーションの書き方

TypeScriptでは、nullとundefinedにもそれぞれ型があります。型アノテーション(変数の後ろに書く : 型名)でこう書けます。

let a: null = null;       // null型:nullだけが入る
let b: undefined = undefined; // undefined型:undefinedだけが入る

ただし、実際のコードでこれをそのまま使うことはほとんどありません。次のセクションで説明する「ユニオン型との組み合わせ」が実際の使い方です。

ここでは「nullとundefinedはそれぞれTypeScriptの型として存在する」という事実を押さえておけば大丈夫です。

null / undefinedを含む型の書き方

null _ undefinedを含む型の書き方

「この変数はstringかもしれないし、nullかもしれない」というケースは実際のコードでよくあります。そういう場合はユニオン型で表現します。

ユニオン型で「null込みの型」を表現する

ユニオン型は 型A | 型B と書くことで「AまたはB」を表せます。null/undefinedをユニオン型と組み合わせるのが基本的な書き方です。

let userName: string | null = null; // 最初はnull、後でstring が入る想定
let count: number | undefined;      // 値が入るかもしれないし、入らないかもしれない

最初は nullundefined が入っていても、後から別の値を代入することができます。

let userName: string | null = null;
userName = "田中"; // OK(string型なので代入できる)
userName = null;   // OK(null型なので代入できる)
userName = 42;     // エラー!(number型は含まれていない)

関数の戻り値にnull/undefinedを含める場合

関数がnullを返す可能性があるときも、戻り値の型をユニオン型で明示します。

// ユーザーが見つからない場合にnullを返す関数
function findUser(id: number): string | null {
  if (id === 1) {
    return "田中";
  }
  return null; // 見つからなかった場合
}

このように書いておくと、この関数を呼び出す側で「nullかもしれない」という前提でコードを書けます。

安全に使うための基本的なチェックパターン

安全に使うための基本的なチェックパターン

null/undefinedを含む型の変数をそのまま使おうとすると、TypeScriptがエラーを出します。

function greet(name: string | null) {
  console.log(name.toUpperCase()); // エラー!
}
Object is possibly 'null'.

このエラーは「name がnullのとき、.toUpperCase() を呼ぶと実行時エラーになるよ」という警告です。安全に使うには、先にnullかどうかを確認する必要があります。

if文で絞り込む(最もシンプルな方法)

最初に覚えるべきパターンはif文による絞り込みです。

function greet(name: string | null) {
  if (name === null) {
    console.log("名前が設定されていません");
    return;
  }
  // ここに来たとき、TypeScriptはnameがstring型と判断してくれる
  console.log(name.toUpperCase()); // エラーなし!
}

if文でnullを除外した後のブロックでは、TypeScriptが「ここでは name はnullじゃない」と自動的に判断してくれます。これを型の絞り込み(Narrowing)と呼びます。

nullとundefinedをまとめてチェックしたい場合は、こう書けます。

function greet(name: string | null | undefined) {
  if (name == null) { // == を使うとnullとundefinedを同時に検出できる
    console.log("名前が設定されていません");
    return;
  }
  console.log(name.toUpperCase()); // エラーなし
}

== null(イコール2つ)はnullとundefinedの両方にマッチします。「まとめてチェックしたい」ときに便利なパターンです。

typeofを使ったundefinedチェック

undefinedのみをチェックしたい場合は typeof を使う方法もあります。

function printValue(value: string | undefined) {
  if (typeof value === "undefined") {
    console.log("値が設定されていません");
    return;
  }
  console.log(value.toUpperCase()); // エラーなし
}

ただし、value === undefined と直接比較する書き方も同じ意味で使えます。どちらか一方を覚えておけば十分です。

「Object is possibly ‘null’」エラーが出たときの対処

Object is possibly 'null' または Object is possibly 'undefined' というエラーは、TypeScriptが「nullかundefinedのとき、このコードが落ちるよ」と教えてくれているサインです。

対処としては、上で紹介したif文によるチェックがもっとも素直な方法です。

const element = document.getElementById("app"); // 戻り値は HTMLElement | null

// そのまま使おうとするとエラー
element.textContent = "Hello"; // ❌ Object is possibly 'null'

// if文でチェックしてから使う
if (element !== null) {
  element.textContent = "Hello"; // ✅ OK
}

document.getElementById() のようなDOM操作系のAPIはnullを返す可能性があるため、TypeScriptではこのエラーがよく出ます。if文でチェックしてから使うことを習慣にしましょう。

strictNullChecksの仕組み

strictNullChecksの仕組み

「Object is possibly ‘null’」というエラーが出るのは、TypeScriptの strictNullChecks というコンパイラオプションが関係しています。このオプションが何をしているかを知っておくと、エラーの意味が腑に落ちやすくなります。

strictNullChecksが無効だとどうなるか

strictNullChecks無効のとき、TypeScriptはnullやundefinedをどんな型の変数にも代入できるものとして扱います。

// strictNullChecks: false のとき
let name: string = null; // エラーにならない(でも実行時にバグになりうる)

型チェックをすり抜けてしまうため、実行してみて初めてエラーに気づく、ということが起きやすくなります。

strictNullChecksを有効にする

strictNullChecks有効にすると、TypeScriptが「この変数にはnullが入るかもしれない」という状況を型レベルで検知できるようになります。その結果、「Object is possibly ‘null’」のようなエラーが出るわけです。一見うるさく感じますが、実行前にバグに気づけるTypeScriptの恩恵をフルに受けられる設定です。

tsconfig.jsonでの設定はこうなります。

{
  "compilerOptions": {
    "strictNullChecks": true
  }
}

なお、strict: true という設定でも strictNullChecks は自動的に有効になります。strict はnull/undefinedのチェックを含む複数の型チェックをまとめてオンにするオプションで、TypeScriptプロジェクトではよく使われる設定です。どちらかが有効になっていれば、この節で説明したエラーが出るようになります。

有効にするとエラーになるケース

// strictNullChecks: true のとき
let name: string = null; // エラー! null は string 型に代入できない
Type 'null' is not assignable to type 'string'.

「なんでいきなりエラーが増えるんだ」と感じるかもしれませんが、これはTypeScriptが「ここにnullが入ると危ないよ」と教えてくれているサインです。前のセクションで紹介したチェックパターンでエラーを修正することで、実行時のバグを未然に防げます。

nullとundefinedの使い分け方針

nullとundefinedの使い分け方

実際にコードを書くとき「これはnullにすべきか、undefinedにすべきか」で迷うことがあります。明確なルールはありませんが、一般的な方針を紹介します。

迷ったらundefinedに統一するのがシンプル

TypeScript(JavaScript)ではundefinedが自然に発生します。変数を宣言しただけでundefinedになりますし、オプションのプロパティや引数はundefinedになります。

このため、「値がないことの表現」をundefinedに統一するとコードが一貫しやすくなります。サバイバルTypeScriptなどのTypeScriptガイドでも、この方針が推奨されています。

// undefinedで統一する例
type User = {
  name: string;
  age?: number; // 省略可能なプロパティはundefined(?をつけるとundefinedになる)
};

最初のうちは「とりあえずundefinedに統一する」という方針でコードを書いてみましょう。

nullを使う場面 — 「意図的な空」を明示したいとき

とはいえ、nullが役立つ場面もあります。代表的なのは「値が意図的に空であること」を他の開発者(または将来の自分)に伝えたいときです。

type FormField = {
  value: string | null; // nullは「ユーザーが意図的に未入力にした」を表す
};

たとえばフォームの入力欄で、「まだ入力されていない(undefined)」と「意図的に空にした(null)」を区別したいような場面では、nullが意味を持ちます。

ただ、初学者のうちはこの区別をあまり意識しすぎなくて大丈夫です。「undefinedを使う、どうしても区別が必要なときだけnullを使う」という程度の理解でコードは書けます。

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


さらに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プログラマーになれるはずです。


まとめ — null/undefinedを型で意識することで何が変わるか

まとめ — null_undefinedを型で意識することで何が変わるか

この記事で扱ったポイントを整理します。

  • nullは「意図的な空」、undefinedは「まだ値がない」 という意味の違いがある
  • TypeScriptではnullとundefinedはそれぞれ独立した型として存在する
  • strictNullChecks: true を有効にすると、null/undefinedを型レベルで管理できる
  • null/undefinedを含む型は string | null のようにユニオン型で表現する
  • 安全に使うには if文による絞り込み が基本。チェック後はTypeScriptが型を自動的に絞り込んでくれる
  • 「Object is possibly ‘null’」エラー はif文でチェックすることで解消できる
  • 迷ったら undefinedに統一する のがシンプルで扱いやすい

null/undefinedを型で意識するようにすると、「実行してみたら落ちた」という状況を事前に防ぎやすくなります。最初は少し面倒に感じるかもしれませんが、すぐに感覚がつかめてくるようになるでしょう。

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