3
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

undefinedについて

Last updated at Posted at 2020-07-17

JavaScript, TypeScriptでは値がないことを示す値として、多くの言語にもあるnullに加えてundefinedもあります。

使い分けについてとやかくいうつもりはありませんが、傾向として設定していないときの「ない」に関してはundefinedを値として使うことが多いので意図的に「ない」を意味したいときはnullを使うほうが他のエンジニアに対して「ない」ことにしていることを伝えられるでしょう。

それがundefinedであるか ?

ある変数定数がundefinedであるかの判定は普通に考えれば以下です。

const ifUndefined = (variable: unknown): variable is undefined => {
  return variable === undefined;
};

これはもちろん正しいのですが、歴史的背景から他の方法も存在します。

歴史的な背景

undefinedは今でこそ定数となりましたが、かつてはglobalにある変数でした。そのため上書きができました。

undefined = '👶';

上書きされてしまうと前項で述べた方法ではその値がundefinedであるかはわかりません。

どうやって判定しますか

プリミティブ型の型判定に使うtypeofを使います。

const ifUndefined = (variable: unknown): variable is undefined => {
  return typeof variable === 'undefined';
};

これは現在undefinedが上書きされているかどうかを問いません。もしも古いES(ES5以前)でも使えるようなパッケージを公開することが視野にある場合は単なる等値比較ではなく、こちらを使うようにするのが無難です。

上書きされたundefinedは元に戻りませんか

以下のようにして戻すことができます。

undefined = void 0;

voidを使います。void 0としていますがこの0はどのような値でも問題ありません。

console.log(typeof void 0  === 'undefined');
// true
console.log(typeof void 1  === 'undefined');
// true
console.log(typeof void '👶'  === 'undefined');
// true
console.log(typeof void null  === 'undefined');
// true
console.log(typeof void new Error()  === 'undefined');
// true

このvoidはTypeScriptで使われる型のvoidとは異なるものです。

おまけ

null

nullundefinedと異なり、初めから定数値(リテラル)として定義されているため、上書きができません。そのため直接等値比較ができます。

const isNull = (variable: unknown): variable is null => {
  return variable === null;
};

逆に

typeof nullとしても'null'という文字列を得ることはできません。typeof null'object'となってしまいます。

console.log(typeof null);
// 'object'

これはTypeScriptでtypeofをやったことがあるかたはおわかりいただけるかと思います。typeof variable === 'object'としたときのif, switchのブロックはvariableの型はobject | nullです。

if (typeof variable === 'object') {
  // variable may be object | null
}

そのため、変数定数がobjectであることを確定させたいときはtypeofのあとにnullかどうかの等値比較をする必要があります。

const isObject = (variable: unknown): variable is object => {
  if (typeof variable === 'object') {
    // object | null
    if (variable !== null) {
      // object
      return true;
    }
    // null
  }
  // unknown
  return false;
};

この比較の順番を逆にするとTypeScriptは変数定数がobjectであることを確定させることができません。これはTypeScriptのType predicateが関係しています。

const isObject = (variable: unknown): variable is object => {
  if (variable !== null) {
    // unknown
    if (typeof variable === 'object') {
      // object | null
      return true;
    }
    // unknown
  }
  // unknown
  return false;
};

TypeScriptが解釈しているifの時点での型をコメントで書いてありますので参照ください。なお、この関数isObject()はTypeScriptによる型の絞り込みは失敗していますが、両方とも同じように動作します。

3
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?