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

Rares Matei
InstructorRares Matei
Share this video with your friends

Social Share Links

Send Tweet
Published 6 years ago
Updated 6 years ago

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.

Instructor: [00:00] Let's say I have two interfaces, one for admin and another for a normal user. I have a function, redirect, that accepts an object as an argument that can be either an admin or a user.

[00:11] Now, if the user is an admin, I want to redirect to a specific route on my page and pass in this admin-only property. Otherwise, I want to use the normal route and pass in just the email, which is a user-only property.

[00:27] Now, what can we write in here to have it pass only if the user is an admin? We can ask TypeScript to assume that the user is an admin and then check if a specific admin-only property is defined on it -- in this case, the role.

[00:42] Even though we can tell visually that this line of code will only get executed if the user is an admin, TypeScript can't make that inference and it's throwing an error here because it still can't be sure that our object is an admin. It thinks it might still be a user, and users don't have a role property on them.

[01:01] I can also create a custom type guard right below here. If this returns true, then the user is an admin. That fix our problem.

[01:12] If I hover over user in this context, you can see TypeScript knows it's an admin. But that might become a bit too much if we start creating these functions every time we need TypeScript to infer types based on simple properties.

[01:27] There is, of course, a third option. The JavaScript in operator is useful for checking if certain properties exist on objects. In this case, all I want to check if the property role exists on my argument.

[01:41] Since TypeScript 2.7, the compiler will now start to infer the type of an object in a block that wraps a condition containing the in operator. In this case, TypeScript will essentially think, "OK, so my input can only be of type admin or user."

[02:00] If it passes that if condition, that means it has the role property on it. Out of admin and user, the only type that includes the role property is admin. That means in this block it must be admin. We can confirm that by hovering over it.

[02:16] This is great. All of the errors went away now, both in the first block and in the second else block. If I want to use user for something else here, you can see I only get suggestions for admin properties, which is ID and role.

[02:29] Also, because I marked my argument as either an admin or a user, and since we confirmed that if it goes in the if block it's an admin, that means that it's only going to go in the else block if it's a user.

[02:40] We can confirm this by trying to access some properties on it. We can see that I now only get user properties. I only get email. TypeScript will keep doing this intelligent inference in all of our logic branches.

[02:52] To recap, we've seen how TypeScript can confer the type of an object based on conditions like this. While custom type guards work great for that purpose, they might add unnecessary indirection to our code, so we can use the JavaScript in operator to both check if a property exists on an object and to hint to the TypeScript compiler about the type of that object.