`{}` 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
ts
const a = 1;a.__proto__.__proto__ === Object.prototype; // trueconst b = symbol();b.__proto__.__proto__ == Object.prototype; // true
ts
const 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
.
ts
let a: Object = 1;let b: Object = {};let c: Object = new Map();
ts
let 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
ts
declare let a: {};declare let b: Object;a = b;b = a;
ts
declare 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.
ts
leta :{} = {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}}
ts
leta :{} = {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.
ts
constobj =Object .create (null);
ts
constobj =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
{}
.