JavaScriptでプログラムを記述する際、変数のデータ型を正しく把握することは、バグを未然に防ぎ、堅牢なコードを書くために非常に重要です。
JavaScriptは動的型付け言語であるため、変数に代入される値の型が実行時に変化することがあります。
このような特性を持つJavaScriptにおいて、値の型を確認するための最も基本的かつ強力な手段がtypeof演算子です。
本記事では、typeof演算子の基本的な使い方から、実務で直面しやすい注意点、さらには配列やnullの正確な判定方法までを詳しく解説します。
初心者の方はもちろん、中級者以上の方にとっても、JavaScriptの型システムを再確認する機会として役立つ内容となっています。
typeof演算子の基本概念と構文
typeofは、後に続くオペランド(値や変数)のデータ型を、文字列として返す演算子です。
基本的な構文には、以下の2種類が存在します。
// 1. 演算子として使用(推奨)
typeof オペランド
// 2. 関数のような形式で使用
typeof(オペランド)
一般的には、括弧を付けない前者の記述方法が多く用いられます。
typeofは関数ではなく演算子であるため、括弧は必須ではありません。
返される値はすべて小文字の文字列であることを覚えておきましょう。
例えば、数値なら"number"、文字列なら"string"が返されます。
各データ型における判定結果の一覧
JavaScriptに存在する主要なデータ型に対して、typeofがどのような結果を返すかを整理しました。
以下の表は、各値とその判定結果をまとめたものです。
| 値の種類 | 例 | typeof の結果 |
|---|---|---|
| 未定義 | undefined | "undefined" |
| 数値 | 10, 3.14, NaN | "number" |
| 文字列 | "Hello" | "string" |
| 真偽値 | true, false | "boolean" |
| BigInt | 10n | "bigint" |
| シンボル | Symbol() | "symbol" |
| 関数 | function() {} | "function" |
| オブジェクト | {}, [] | "object" |
| null | null | "object" |
この表からわかるように、プリミティブ型の多くは直感的な結果を返します。
しかし、後述するようにnullや配列に関しては注意が必要です。
プリミティブ型の判定例
まずは、日常的な開発で頻繁に使用するプリミティブ型の判定コードを見てみましょう。
// 文字列の判定
console.log(typeof "JavaScript");
// 数値の判定
console.log(typeof 123);
// NaNも数値型として扱われる点に注意
console.log(typeof NaN);
// 真偽値の判定
console.log(typeof true);
// 未定義の判定
let x;
console.log(typeof x);
"string"
"number"
"number"
"boolean"
"undefined"
数値の判定において、数値ではないことを示すNaN(Not-a-Number)が“number”を返す点は、JavaScriptの有名な挙動の一つです。
これは、仕様上の定義によるものであり、数学的な意味での数値ではなく、データ型としての数値を指しています。
モダンなデータ型の判定(BigInt, Symbol)
比較的新しいJavaScriptの仕様で追加された型についても、typeofは対応しています。
// BigInt(巨大な整数)
const bigIntNum = 9007199254740991n;
console.log(typeof bigIntNum);
// Symbol(一意な識別子)
const sym = Symbol("id");
console.log(typeof sym);
"bigint"
"symbol"
これらの型を扱う際も、typeofを使用することで、従来の数値や文字列と区別することが可能です。
関数の判定
JavaScriptにおいて、関数は特別なオブジェクトとして扱われますが、typeofは一貫して“function”を返します。
// 通常の関数定義
function sayHello() {}
console.log(typeof sayHello);
// アロー関数
const greet = () => {};
console.log(typeof greet);
// クラスも内部的には関数のため"function"を返す
class MyClass {}
console.log(typeof MyClass);
"function"
"function"
"function"
これにより、ある変数が実行可能な関数であるかどうかを、簡潔にチェックすることができます。
ただし、クラスそのものは関数として判定されますが、そのインスタンスはオブジェクトとして判定される点に留意してください。
typeof使用時の重要な注意点と落とし穴
typeof演算子は非常に便利ですが、開発者を悩ませるいくつかの「落とし穴」が存在します。
これらの挙動を正確に理解しておくことが、バグの少ないコーディングへの近道です。
nullの判定が”object”になる理由
JavaScriptにおける最大の注意点の一つは、typeof null が “object” を返すという事実です。
const data = null;
console.log(typeof data);
"object"
本来、nullは「値が存在しない」ことを示すプリミティブ型ですが、歴史的な実装上の理由によりオブジェクトとして判定されます。
これはJavaScriptの初期の実装ミスとされていますが、既存のWebサイトへの影響を考慮し、現在も修正されていません。
したがって、変数がオブジェクトであることを判定したい場合に typeof obj === "object" と記述すると、null の場合も条件を通過してしまいます。
これを避けるためには、以下のように厳密な等価演算子を組み合わせてチェックを行う必要があります。
// 安全なオブジェクト判定の例
if (obj !== null && typeof obj === "object") {
// ここではobjがnullでない真のオブジェクトであることが保証される
}
配列も”object”として判定される
もう一つの注意点は、配列(Array)も “object” として判定されることです。
const list = [1, 2, 3];
console.log(typeof list);
"object"
JavaScriptでは配列はオブジェクトの一種であるため、この結果自体は間違いではありません。
しかし、プログラム内で「純粋なオブジェクト」と「配列」を区別したい場合には、typeofだけでは不十分です。
配列かどうかを正確に判定するには、Array.isArray() メソッドを使用するのが標準的です。
const list = [1, 2, 3];
if (Array.isArray(list)) {
console.log("これは配列です");
}
実務での活用:型チェックによる安全性の向上
実際のアプリケーション開発において、typeofがどのように役立つかを見ていきましょう。
主に、関数の引数チェックや、外部APIから取得したデータの検証などで活用されます。
引数の型バリデーション
関数が期待通りの型を受け取っているかを確認することで、予期せぬエラーを防ぐことができます。
function calculateTotal(price, tax) {
// 引数が数値でない場合にエラーを投げる
if (typeof price !== "number" || typeof tax !== "number") {
throw new Error("引数は数値でなければなりません");
}
return price + (price * tax);
}
try {
console.log(calculateTotal(100, 0.1));
console.log(calculateTotal("100", 0.1)); // ここでエラー
} catch (e) {
console.error(e.message);
}
このように、関数の入り口で型をチェックする手法は「ガード節」と呼ばれ、コードの可読性と堅牢性を高めます。
未定義変数の存在確認
typeofの非常に強力な特徴として、定義されていない変数を参照してもエラーにならないという点があります。
通常の変数を直接参照しようとすると ReferenceError が発生しますが、typeofを介せば安全に確認できます。
// undeclaredVariable は定義されていないと仮定
if (typeof undeclaredVariable !== "undefined") {
// 変数が存在する場合の処理
} else {
console.log("変数は定義されていません");
}
この性質は、ブラウザのグローバル変数や特定のライブラリがロードされているかを確認する際に非常に便利です。
より高度な型判定:typeof以外の選択肢
typeofだけでは解決できないケースに対応するため、他の型判定手法も知っておくと役立ちます。
instanceof演算子
instanceofは、あるオブジェクトが特定のクラス(またはコンストラクタ)のインスタンスであるかどうかを判定します。
const now = new Date();
console.log(now instanceof Date);
console.log(now instanceof Object);
true
true
typeofでは "object" としか判定されない日付データや独自のクラスインスタンスを識別するのに適しています。
Object.prototype.toString.call()
より厳密に、かつ詳細な型情報を取得したい場合には、以下のイディオムが使われることがあります。
const checkType = (val) => Object.prototype.toString.call(val);
console.log(checkType([]));
console.log(checkType(null));
console.log(checkType(new Date()));
"[object Array]"
"[object Null]"
"[object Date]"
この方法は、typeofの欠点を補い、あらゆる組み込みオブジェクトの種類を正確に特定するための最も信頼性の高い方法の一つです。
まとめ
JavaScriptのtypeof演算子は、変数の型を素早く判定するための不可欠なツールです。
文字列、数値、真偽値といったプリミティブ型の判定には非常に有効ですが、nullが"object"になる点や、配列とオブジェクトの区別ができない点には注意が必要です。
開発の現場では、基本的にはtypeofを用い、必要に応じてArray.isArray()やinstanceofを組み合わせるのが最適なアプローチと言えるでしょう。
また、TypeScriptなどの静的型付けツールを導入しているプロジェクトであっても、実行時のデータ(APIレスポンスなど)を扱う際には、依然としてtypeofによる動的なチェックが重要な役割を果たします。
本記事で解説した特性と注意点を踏まえ、より安全で品質の高いJavaScriptコードを構築していきましょう。
