TypeScriptには似たような型としてObject
型とobject
型と{}
型が存在します。
let o1: Object; let o2: object; let o3: {};
今回はこの3つの使い分け、あるいはobject
型導入の経緯についてです。
JavaScriptのデータ型
データ構造 - JavaScript | MDNを読めば分かるように、
- Boolean
- Null
- Undefined
- Number
- String
- Symbol
の6種のプリミティブ型を持つプリミティブ値とオブジェクトでJavaScriptは成り立っています。
TypeScriptにおけるobject
型とはここでいうプリミティブ型以外を表現しています。
object
型はいつ使われるのか
いつ役に立つかというとObject.create()
の定義です。
TypeScript/lib.d.ts at master · Microsoft/TypeScript · GitHub
/** * Creates an object that has the specified prototype, and that optionally contains specified properties. * @param o Object to use as a prototype. May be null * @param properties JavaScript object that contains one or more property descriptors. */ create(o: object | null, properties: PropertyDescriptorMap & ThisType<any>): any;
Object.create()
の第一引数はobject | null
です。したがってObject.create('str')
やObject.create(4403)
などはエラーとなります。
Object
型とは何か
これは単純にObject
オブジェクトの構造を記述するためのInterfaceです。
追記
Object
オブジェクトの型はObjectConstructor
なので、Object
型は全てのオブジェクトに共通する構造を記述するInterfaceといったほうが正しかったです。
{}
型とは何か
これは{}
のようなオブジェクトリテラルで書かれる、プロパティを持たないオブジェクトの型を表現しています。ただしJavaScriptなので{}
オブジェクトはプロトタイプチェーンの結果Object
オブジェクトのメソッドやプロパティが利用できるはずなので、結果として{}
型とObject
型は実質同じ型となっています。
使い分け
というわけで普通我々が使う場合は大体{}
型です。
オブジェクト共通の構造を示したい場合はObject
型を使いましょう。
object
型を使うのはプリミティブ型ではいけない場合です。つまりどういうことは導入の経緯とともに見ていきます。
object
型導入の経緯
プリミティブ型でもObject
型に定義されたメソッドやプロパティが使える
JavaScriptの仕様上true.toString()
のなどの呼び出しが可能です(true
はプリミティブ値なのにObject
オブジェクトのメソッドを呼んでいる)。何故これが可能かと言えば暗黙的にオブジェクトが生成されているからです。つまりtrue.toString()
は(new Boolean(true)).toString()
と同等です。
この暗黙的生成を表現するためTypeScriptではプリミティブ型はObject
型の構造も含んでいます。
この仕様で起こる問題
TypeScriptはStructural subtypingを採用しているので、Object.create()
の型定義ができないことになります。
つまり
create(o: Object | null, properties: PropertyDescriptorMap & ThisType<any>): any;
としてしまうとObject
型を満足する変数やリテラルを引数に取れることになります。すると例えば"str"
(string
型)は先ほど説明した仕様によりObject
型を満足させられるのでObject.create("str")
はTypeScript上ではエラーとして検出されません。JavaScriptとして実行された時初めてエラーになります。
これがobject
型という非プリミティブ型を表現する型が導入された経緯です。
使い分けないと困るのか
object
型が導入された経緯みたいな話はありますが、{}
型とObject
型に関して言えばどっち使っても極端に困ることないと思います(ただしIDEの補完については多少差がでます)。気分の問題と言えば気分の問題ですが似たようなものがある意味くらいは知っておく良いかと思います。