`{}` vs `object` vs `Object` in TypeScript.
With this post Iâll never be confused again about their difference.
type Object
The type Object refers to the Object constructor in JavaScript.
Recall the prototype chain, (almost) every object has Object.prototype at the end of their prototype chain, so (almost) every object is instance of Object.
ts({}).__proto__ === Object.prototype // true([]).__proto__.__proto__) === Object.prototype); // truenew Map().__proto__.__proto__ === Object.prototype; // true
ts({}).__proto__ === Object.prototype // true([]).__proto__.__proto__) === Object.prototype); // truenew Map().__proto__.__proto__ === Object.prototype; // true
For primitive values(except null and undefined), when calling the methods on them, a wrapper object will be created so primitive values have the prototype chain as well
tsconst a = 1;a.__proto__.__proto__ === Object.prototype; // trueconst b = symbol();b.__proto__.__proto__ == Object.prototype; // true
tsconst a = 1;a.__proto__.__proto__ === Object.prototype; // trueconst b = symbol();b.__proto__.__proto__ == Object.prototype; // true
So, every non-null values could be typed as Object.
tslet a: Object = 1;let b: Object = {};let c: Object = new Map();
tslet a: Object = 1;let b: Object = {};let c: Object = new Map();
But Object type is not recommended officially.
â Donât ever use the types Number, String, Boolean, Symbol, or Object These types refer to non-primitive boxed objects that are almost never used appropriately in JavaScript code.
type {}
{} is an empty object literal and it is (almost) the same as Object - meaning they are assignable to each other, TypeScript doesnât complain about code below
tsdeclare let a: {};declare let b: Object;a = b;b = a;
tsdeclare let a: {};declare let b: Object;a = b;b = a;
Then whatâs the difference ? The slight difference is that Object is more stricter about the prototype methods.
tsleta :{} = {toString () {return 3}}Âletb :Object = {Type '() => number' is not assignable to type '() => string'. Type 'number' is not assignable to type 'string'.2322Type '() => number' is not assignable to type '() => string'. Type 'number' is not assignable to type 'string'.() { toString return 3}}
tsleta :{} = {toString () {return 3}}Âletb :Object = {Type '() => number' is not assignable to type '() => string'. Type 'number' is not assignable to type 'string'.2322Type '() => number' is not assignable to type '() => string'. Type 'number' is not assignable to type 'string'.() { toString return 3}}
We can see that Object strictly checks the return type, but {} ignore the return value. I donât know why.
Why I mention (almost) in previous section about Object is that we actually can create some object which doesnât fall into its category.
tsconstobj =Object .create (null);
tsconstobj =Object .create (null);
This obj doesnât have prototype, so obj.toString() throws an error while TypeScript types it as any which is not sound.
In my humble opinion, {} would be a better option to type it if TypeScript has make it explicit about such nuances, since clearly this obj is not of type Object. But as shown above, {} and Object doesnât make much difference for now.
object
object simply represents non primitive values, meaning NOT number, string, symbol, null, boolean, undefined or bigint. (ref)
Summary
So now we can understand why unknown means {} | null | undefined, and here is the rule of thumb:
- for the objects we usually means, use
object. - for non-null values, use
{}.
