サイトトップ

Director Flash 書籍 業務内容 プロフィール

HTML5テクニカルノート

TypeScriptハンドブック 06: nullとundefinedなど


TypeScript公式「Handbook」の「Everyday Types」から最後にご紹介するのは、おもにnullundefinedに関わる項目です(かっこ内は原文の項目タイトル)。そして、その他として若干の説明を補っています。

01 nullとundefined

JavaScriptのプリミティブには、用いることのできる値がないことを示すnullと、初期化されていない値を意味するundefinedがあります。TypeScriptが備えるこれらに対する型は、同じ名前のnullundefinedです。ふたつの型がどう扱われるかは、tsconfig.jsonstrictNullChecksの設定によって変わります。

ノート01■TSConfigのstrictフラグ

tsconfig.jsonstricttrueにすると、すべての厳格な(strict)モードが有効になります。つまり、strictNullCheckstrueにした効果が得られるということです。

01-01 strictNullChecksがfalseのとき

strictNullChecksfalseがデフォルトです。この場合、nullundefinedは、すべての型に値として代入できます。

let greeting = "Hello";
greeting = null;  // OK
greeting = undefined;  // OK

けれど、予め定めたのとは異なる値が入ると、バグの原因になりかねません。とくに、オブジェクトの参照が取得できずにnullとなった場合、プロパティやメソッドを参照すればランタイムエラーになってしまいます。とくに必要性がないなら、strictNullCheckstrueにするのがよいでしょう。


const item = document.getElementById("item");  // 要素の参照が取得できない場合
item.textContent = "item 01";  // コンパイルエラーなし
// ランタイムエラー: Uncaught TypeError: Cannot set property 'textContent' of null

01-02 strictNullChecksがtrueのとき

strictNullCheckstrueに定めると、nullundefinedが型づけに含まれないかぎり、これらの値は受け入れられません。


let greeting = "Hello";
// 型 'null' を型 'string' に割り当てることはできません。
greeting = null;
// 型 'undefined' を型 'string' に割り当てることはできません。
greeting = undefined;

nullundefinedが受け取れるようにするには、ユニオン型ではっきりとnullまたはundefinedを加えてください。その場合、nullundefinedとは型が区別されます。


let greetingWithNull: string | null = "Howdy";
greetingWithNull = null; // OK
// 型 'undefined' を型 'string | null' に割り当てることはできません。
greetingWithNull = undefined;

取り出したオブジェクトの参照がnullかもしれない場合には、そのままプロパティやメソッドにアクセスすることは許されません。コンパイルエラーが示されます。


const item = document.getElementById("item");
// コンパイルエラー: オブジェクトは 'null' である可能性があります。
item.textContent = "item 01";

エラーを避けるには、プロパティやメソッドにアクセスする前に、オブジェクトが取り出せたことを確かめてください。これで、ランタイムでもエラーが起こりることはありません。


if (item) {  // オブジェクトの存在を確認
  item.textContent = "item 01";
}

01-03 非nullアサーション演算子!

nullundefinedでないかの判定を、型アサーションの構文で省くこともできます。用いるのは、非nullアサーション演算子!です。式の後に!演算子を添えると、値がnullでもundefinedでもないことを型アサーションします。


const item = document.getElementById("item");
item!.textContent = "item 01";  // コンパイルエラーなし

けれど、型アサーションはデータを変換する訳ではありません。TypeScriptに、値がnullundefinedとなり得るかの分析を止めさせるだけです。オブジェクトの参照が得られなかったのにプロパティやメソッドにアクセスすれば、ランタイムエラーになってしまいます。

02 その他

今のところは存在だけ覚えておけばよい型を、いくつかご紹介します。

02-01 列挙型(enum)

列挙型(enum)は、TypeScriptがJavaScriptに加えた機能で、列挙した名前の低数値をまとめたデータです。TypeScriptの他の機能と異なり、JavaScriptに型を定めただけでなく、言語とランタイムの拡張になります。列挙型について理解するまでは、こういう型があることだけ覚えておけば構いません。列挙型について詳しくは、リファレンスの「Enums」をご参照ください。

02-02 あまり一般的でないプリミティブ

TypeScriptの型システムにおいて、あまり一般的でないJavaScriptのプリミティブをふたつ簡単にご説明します。

bigInt型

BigIntのデータは、 数値(number)型プリミティブで表現できる最大の数であるNumber.MAX_SAFE_INTEGERよりも大きな数値を扱えるプリミティブです。ECMAScript 2020で採り入れられました(「JavaScriptの次の仕様ES2020で追加されることが決定した新機能まとめ」参照)。

通常の数値型のままでは、Number.MAX_SAFE_INTEGERを超えた数値の演算に誤差が生じてしまいます。


const maxInt = Number.MAX_SAFE_INTEGER;
const maxIntPuls2 = maxInt + 2;
console.log(maxIntPuls2 - maxInt);  // 1 <- 誤差が生じる

bigint型の数値をつくるのが、BigInt()関数です。数値のあとにnを添えて、リテラルで書くこともできます。


const maxIntBig = BigInt(Number.MAX_SAFE_INTEGER);
const maxIntPlus2Big = maxIntBig + 2n;
console.log(maxIntPlus2Big - maxIntBig);  // 2n

bigint型について詳しくは、リファレンスの「BigInt」をお読みください。

symbol型

ECMAScript 2015で備わったSymbolのプリミティブは、グローバルに一意の値です。Symbol()関数でつくり、引数には説明のための文字列が渡せます。ただし、引数の文字列から値がつくられるわけではありません。戻り値は、つねに一意のsymbol型プリミティブです。


const name = Symbol("name");
console.log(name === Symbol("name"));  // false

symbol型について詳しくは、リファレンスの「Symbols」をご覧ください。


作成者: 野中文雄
作成日: 2021年06月03日


Copyright © 2001-2020 Fumio Nonaka.  All rights reserved.