どっちのtypeof?
typeof
2種類の値の型情報を取得するための演算子としてtypeof
という演算子があります。このtypeof
にはJavaScriptで使用されているtypeof
とTypeScriptの型演算子としてのtypeof
があります。
typeof
演算子
JavaScriptのJavaScriptにおけるtypeof
演算子は、値の型を文字列で返す演算子です。
JavaScriptの型について、typeof
は以下のような値を返します。
Type |
typeof の返り値 |
---|---|
Null | "object" |
Undifined | "undefined" |
Boolean | "boolean" |
Number | "number" |
String | "string" |
Bigint | "bigint" |
Symbol | "symbol" |
関数オブジェクト | "function" |
その他のオブジェクト | "object" |
以下のコードのようにオブジェクトの型をプロパティを含めて詳しく見たいと思っても、"object"
しか返ってきません。これは、JavaScriptのtypeof
演算子が文字列を返しているからというわけですね。
const obj = {
num: 1,
str: 'one'
}
console.log(typeof obj)// "object"
typeof
はnull
に対しても"object"
を返すという点にも注意が必要です。
console.log(typeof {num: 1} === typeof null) //true
この挙動はJavaScriptのバグなのですが、"null"
を返すよう修正を行なってしまうと既存のコードが破壊されることが懸念されるため、修正はされない方針となっているようです。
In JavaScript, typeof null is 'object', which incorrectly suggests that null is an object (it isn’t, it’s a primitive value, consult my blog post on categorizing values for details). This is a bug and one that unfortunately can’t be fixed, because it would break existing code. Let’s explore the history of this bug.
typeof
型演算子
TypeScriptのTypeScriptにも値の型情報を得るための演算子としてtypeof
があります。
こちらはtypeof
型演算子(Typeof Type Operator)と呼ばれ、typeof
演算子と区別されています。
const obj : {
num: number
str: string
} = {num: 1, str: 'one'}
// type T = {
// num: number;
// str: string;
// }
type T = typeof obj
//const t: "string" | "number" | "bigint" | "boolean" | "symbol" | "undefined" | "object" | "function"
const t = typeof obj
このコード例では、型T
はオブジェクトのプロパティを含めて詳細な型情報をtypeof
型演算子で取得できています。
一方、typeof
演算子によってobj
の型に関する文字列を代入されている変数t
はtypeof
演算子が返しうる文字列のユニオン型であると型推論がされています。
typeof obj
がどのような文字列を返すかはJavaScriptのtypeof
が実行されるまでわからないため、このような型推論がされているわけですね。
typeof
演算子とtypeof
型演算子の見分け方
同じ綴りの演算子があると混乱してしまいそうですが、typeof
型演算子はリテラル型の"foo"
や123
と同様に、型注釈などの型を記述する場面でのみ使用することが可能ですので、どこに記述されているかに着目することで見分けられます。
const obj = {str: 'foo'}
//const obj2: { str: string; }
const obj2: typeof obj = {str: typeof obj}
console.log(obj2.str) //"object"
上のコード例で出てくる1つ目のtypeof
は型注釈として使用されていますので、型演算子の方のtypeof
であるとわかります。
2つ目のtypeof
については、オブジェクトリテラルに含まれるstr
プロパティの値として記述されていますので、typeof
演算子の方であるとわかります。
TypeScriptにはtypeof
の他にもリテラル型など、JavaScriptでは別の意味をもつが同じ書き方がされる機能がいくつかあります。
どちらの機能なのかわからなくなった時には、記述位置が型が期待される箇所なのか、値が期待される箇所なのかを考えてみると見分けがつくはずです。
Discussion