Use the JavaScript “in” operator for automatic type inference in TypeScript

Share this video with your friends

Send Tweet

Sometimes we might want to make a function more generic by having it accept a union of different types as an argument. Using the JavaScript “in” operator, we can test for the presence of different properties on the argument object, and TypeScript will automatically infer the exact type of our object in that block. It does this by looking at all the possible types in the union and then keeping only the ones that have that specific property defined.

jay shah
jay shah
~ 6 years ago

The javascript "in" operator looks all the way into the prototype chain, so what type does it know to assume then?

Jean-Denis Vauguet
Jean-Denis Vauguet
~ 6 years ago

TypeScript provides static typing. The "in" operator is a runtime construct. Basically "in" has nothing to do with TypeScript's types/interfaces. It merely checks whether, at runtime, some object has some property, all the way into that object's prototype chain indeed. So "in" does not assume anything/any type. That's a known limitation to the TypeScript model, that is: it compiles to JavaScript, so typing information is lost and it's up to the programmer mimicking the typing logic through properties check and whatnot.

If you're looking for runtime type checking with TypeScript, you might try https://github.com/fabiandev/ts-runtime but it's not officially supported by any means.

JP Lew
JP Lew
~ 6 years ago

What's the difference between writing if("role" in usr) and if(usr.role)?

Steeve
Steeve
~ 5 years ago

Wow this is horrible. How is there not a built-in way to check for a specific type?

The day someone adds a role attribute to User people will be redirected to the Admin route?

Rares Matei
Rares Matei(instructor)
~ 5 years ago

Wow this is horrible. How is there not a built-in way to check for a specific type?

The day someone adds a role attribute to User people will be redirected to the Admin route?

That's right! It's not at all safe/secure in this case! You'll usually want to use properties that you know will be part of a specific type - in the above example "role" is a property which might exist on a non-admin user as well, so it's not the best example.

But once you're sure a specific property will be part of just a single interface, this is one of the easiest ways to get automatic type inference. As interfaces don't exist in vanilla JS, there's no way to check whether your object is of a specific interface, as that would stop working at runtime - so you need to use the "in" operator as something both JS and TS can understand.

You can definitely check if something is of a specific class though using "typeof"

Rares Matei
Rares Matei(instructor)
~ 5 years ago

What's the difference between writing if("role" in usr) and if(usr.role)?

if(usr.role) will not work in the lesson code. Typescript will complain that the "role" attribute does not exist on something that can be Admin | User. if(usr.role) is assumed to check whether the value of usr.role is defined, and not whether the property actually exists.

So to make TS narrow down to the correct interface for us, we need to if('role' in usr) which simply checks if that property exists on the object (take care that a property can exist even if it's undefined).

Joël
Joël
~ 5 years ago

What's the difference between writing if("role" in usr) and if(usr.role)?

Just for information in JS if you do something like if(usr.role) you are doing implicit cast (coertion). You are NOT checking if property is in the object.

~ 3 years ago

using custom function type guard is much better than in, especially in this example. It is more readable - you want to allow action if object is an Admin, not if it has particular property. Second reason - imagine your data structure for Admin changes, for example property name has changed. Using function you do a change in one place, using in you need to scan whole codebase to change it.