Represent Non-Primitive Types with TypeScript’s object Type

Marius Schulz
InstructorMarius Schulz

Share this video with your friends

Send Tweet

TypeScript 2.2 introduced the object, a type that represents any non-primitive type. It can be used to more accurately type methods such as Object.create. Don't confuse it with the Object type or {}, the empty object type, though!

Before we can take a look at TypeScript's object type, we first have to know the six primitive types in JavaScript, which are Boolean, number, string, symbol, null, and undefined.

TypeScript's object type represents any value that does not have any of the above types. Here I'm declaring a local variable called obj that is of type object. If I now try to assign a value of a primitive type to obj I get a type error every single time.

For example, in line 14 the type checker tells me that type symbol is not assignable to type object, because, again, symbol is a primitive type and object describes all non-primitive types. On the other hand, if I assign a value of a complex type such as an empty object, or an empty array, or a function, the assignment expression type checks just fine.

All of this is useful because there are some methods in the JavaScript standard library that do not accept primitive values. One of these examples is object.create. If we take a look at the type declaration for object.create, we see that the parameter o is typed to be an object or a null.

Therefore, we get an error if we try to pass anything else. This is really helpful because otherwise we would have gotten this error at runtime. Perhaps confusingly TypeScript defines another type called object, which is spelled with an uppercase O.

This type describes functionality that is common to all objects in JavaScript. For instance, the two-string method that hasOwnProperty method and others. If I type obj. I can see all these methods in my auto completion list.

If I now remove the object type annotation and type obj. again I no longer get any auto completion. The obj variable is inferred to be of the empty object type, a type that represents anything that doesn't have any members on its own. This is why the TypeScript language server doesn't offer any auto completion suggestions here.

As you can see in line two, however, the call to the hasOwnProperty method is still type correct, because of course obj is an object and has access to the hasOwnProperty method. At the same time, you cannot add new properties to an object that has the empty object type.

If you wanted to allow such assignments you could add an explicit string index signature via a type annotation. In that case both the method call in line two, and the property assignment in line three, would be type correct. Finally, another solution could have been to type the entire object as any, in which case the compiler would allow, well, anything.

Brendan Whiting
Brendan Whiting
~ 3 years ago

I’m having a hard time understanding primitive types. If null is one of the primitives, why is typeof null ‘object’?. And then why can’t we assign null to something with type object?

Marius Schulz
Marius Schulzinstructor
~ 3 years ago

@Brendan: typeof null evaluating to "object" is a bug that we've been stuck with for two decades (see The history of “typeof null”); unfortunately, it can't be fixed without breaking a ton of JavaScript code.

When you use --strictNullChecks (which you should!), null is not assignable to object. If it were, that would defeat the whole purpose of strict null checking.

Brendan Whiting
Brendan Whiting
~ 3 years ago

Interesting