Skip to content

Instantly share code, notes, and snippets.

@OliverJAsh
Last active May 10, 2019 16:18
  • Star 2 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
Star You must be signed in to star a gist
Save OliverJAsh/381cd397008309c4a95d8f9bd31adcd7 to your computer and use it in GitHub Desktop.
TypeScript object types

JS terminology

  • "primitive": boolean, number, string, symbol, null, undefined
  • "object" aka "non-primitive": any "custom object" (e.g. { foo: 1 }) or function

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Data_structures#Data_types

(In JS, people mistakingly think of primitives as "object"s, but in strict JS terminology, they're not.)

object type

An "object" aka "non-primitive" (as per JS terminology above).

const myObject: object = primitive // error
const myObject: object = customObjectOrFunction // no error

Object type

The class instance behind any "object".

primitive instanceof Object // false
customObjectOrFunction instanceof Object // true

// At first glance, we would expect this to error, so that TS' behaviour matches
// JS's runtime behaviour. However, TS only cares about structures, so this does
// not error.
const myObject: Object = primitive;

const myObject: Object = customObjectOrFunction;

// Note: `Object` value === `ObjectConstructor` type

{} aka "empty object type"

An object but specifically one without any properties (TODO: correct?).

const myObject: {} = {}; // no error

// At first glance, we would expect this to error, but it doesn't. TODO: why?
const myObject: {} = { foo: 1 };

Related

@RyanCavanaugh
Copy link

The reason Object exists is so that TypeScript a place to understand the properties exist on all JavaScript objects which have the global value Object.prototype in their __proto__ chain. In other words, for values which are instanceof Object, those values should appear to have methods like hasOwnProperty (even though the types of those values don't include those properties!). Probably in retrospect this type should have been better-hidden.

An object but specifically one without any properties (TODO: correct?).

Not correct, on two counts.

{} is the empty type and is assignable from any non-null/non-undefined type. Remember structural typing here: Reducing the number of properties in a type (should) never decrease the number of types which are assignable to it (n.b. excess property checking is not a factor in assignability; it is a separate check).

Note some problematic symmetry here: string should be assignable to { length: number }, and for any type { r0; r1; r2...}, a value assignable that type should also be assignable to { r1; r2...}. So if string is assignable to { length: number } (which it absolutely should be), then string must also be assignable to { }, even though it's not an object.

@DanielRosenwasser
Copy link

The biggest observable difference between {} and Object is in type relationships. A { toString: number } is assignable to {}, but not Object.

@dubzzz
Copy link

dubzzz commented Apr 16, 2019

You should also add bigint in the list of primitives

@OliverJAsh
Copy link
Author

{} is the empty type and is assignable from any non-null/non-undefined type

@RyanCavanaugh That makes sense. I've also seen this referred to as the "empty object type", but that is surely misleading, because it's not only assignable to "object"s (under the traditional JS terminology defined above in this gist) but also some primitives (all except null | undefined). This naming is why my intuition lead me to believe {} would be the same as object but specifically one without any properties.

@OliverJAsh
Copy link
Author

{} is the empty type

@RyanCavanaugh I'm worried about the naming here, since "empty type" is commonly understood to mean the "bottom type" aka never:

https://en.wikipedia.org/wiki/Bottom_type

It is also called the zero or empty type

@RyanCavanaugh
Copy link

There isn't a good name that conveys its behavior, which is just sort of a corollary to the fact that unknown / object are usually better choices

@OliverJAsh
Copy link
Author

@RyanCavanaugh Just to check my understanding, is this type hierarchy diagram correct?

object   non-nullable primitive   null   undefined
------------- {} --------------
-------------------- unknown ---------------------

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment