Wait, a video explaining Lookup Types? Yes! Check it out on Egghead.io!
That's something I was wondering for a while. I read the official docs and Marius Schulz post where quite well explain it, but didn't totally get the use of it. I needed to come across a real world case where I had to use it.
Then I made a PR to Jest on DefinitelyTyped repository for adding the spyOn
function introduced in Jest 19. That's when I finally understood it.
What exactly are Lookup types?
Basically a lookup type defines an indexed property type of another type. They are created using the keyof
operator, which returns an union of string literals:
// Given a Bike type
interface Bike {
model: string;
weight: number;
ride: Function;
}
// Get all prop names of Bike
type BikePropNames = keyof Bike; // "model" | "weight" | "ride"
// We can get the all prop types of Bike as well
type BikePropTypes = Bike[BikePropNames]; // "string" | "number" | "Function"
Typescript infers the string literals by looking up on the types used, either for the keyof
operator and element access.
OK... But when can this be useful?
Let's take the jest.spyOn
function, as an example. The function works takes an object as a first parameter, and the method you wanna spy on as a second parameter. I've first wrote it like this:
function spyOn(object: any, method: string);
Yes, this would work. But what if, given the Bike
example, I use a non-existent method as a second parameter?
const bike: Bike = {
model: "Orbea X5",
weigth: 10,
ride: () => console.log("riding!!")
};
// No TS error, but it would fail, since 'blabla' is not a method of bike
spyOn(bike, "blabla");
This is not type-safe, ts will not complain at all. How can we do this type-safe?
function spyOn<O, M extends keyof O>(object: O, method: M)
...
spyOn(bike, 'blabla') // now TS throws an error :)
spyOn(bike, 'ride') // This works
If you still don't understand the spyOn
declaration, basically is saying:
<O, M extends keyof O>
:O
is any object, andM
is a property ofO
object: O, method: M
: we expectO
(any object) as a first parameter, andM
(a property ofO
as a second)
Do you see now the power of lookup types? You can dynamically generate string literal union types! That'll make your type definitions much more accurate 😉