Type inference with the in operator
TypeScript also allows us to test an object for the presence of a property using the in operator. Imagine that we have the following interfaces:
interface IHasIdAndNameProperty { id: number; name: string; } interface IHasDescAndValueProperty { description: string; value: number; }
Here, we have an interface named IHasIdAndNameProperty that defines an id and a name property. We also have an interface named IHasDescAndValueProperty that defines a description and value property. We can then write a function that can work with both interfaces, as follows:
function printNameOrDescription( value: IHasIdAndNameProperty | IHasDescAndValueProperty) { if ('id' in value) { console.log(`found id ! | name : ${value.name}`); } if ('value' in value) { console.log(`found value ! : description : ${value.description}`); } }
Here, we have a function named printNameOrDescription that has a single argument named value. The type of the value argument is a union of the IHasIdAndNameProperty interface and the IHasDescAndValueProperty interface. Note that there is no overlap in properties between the two interfaces, so how do we tell which interface was passed in? In this case, we are using a type guard that is using the in operator:
if ('id' in value)
Our first type guard is testing the argument that is being passed in, and checking for the presence of a property named id. If this is true, then we know that the type that was passed in was of the IHasIdAndNameProperty type, and can therefore print the value of the name property to the console. Similarly, the second type guard is testing for the presence of the value property:
if ('value' in value)
If the value property is found, then we know that the nature of the value argument is of the IHasDescAndNameProperty type, and can log the value of the description property to the console.
Hence, TypeScript allows us to generate type guards for interfaces using the in operator, to test whether an interface has a particular property.