Controlling Inference with Satisfies

Pro Members Only

This lesson is available if you have an active subscription.

Alternatively, some member might be able to gift it to you.

If you already have a subscription, you can sign in.

Controlling Inference with Satisfies

Subscription Required

You must have an active subscription to access this content.
If you already have a subscription, you can sign in.

Challenge

How can we get direction to be inferred as Direction but leave everything else as default?

type Direction = 'north' | 'south' | 'east' | 'west';

const guidance = [
{ direction: 'north', distance: 10 },
{ direction: 'east', distance: 20 },
];

Solution

Using satisfies!

type Direction = 'north' | 'south' | 'east' | 'west';

const guidance = [
{ direction: 'north', distance: 10 },
{ direction: 'east', distance: 20 },
] satisfies ({ direction: Direction } & Omit<any, 'direction'>)[];

Utility

Create a general purpose utility πŸ˜‰

type InferProps<T> = T & Omit<any, keyof T>;

In action πŸƒπŸ»β€β™‚οΈ

type InferProps<T> = T & Omit<any, keyof T>;

type Direction = 'north' | 'south' | 'east' | 'west';

const guidance = [
{ direction: 'north', distance: 10, speed: 50 },
{ direction: 'east', distance: 20, speed: 100 },
] satisfies InferProps<{ direction: Direction }>[];
javascript
typescript
react
playwright

Enjoy free content straight from your inbox πŸ’Œ

No spam, unsubscribe at any time.

Transcript

00:00

For the most part, typescripts builtin inference engine is pretty good on its own, but we do have certain operators which we can use to guide it in a direction that we want. We've already seen how the as cons operator is designed specifically for this purpose of guiding the inference engine. But there are other operators that we can use which have a different primary purpose. However, they do modify the inferred result as a side effect. We can use this to our advantage and once such operator is a satisfies operator. Let's take a look at a motivating example. We have this type for direction, which can be one

00:32

of the string unions, and then we have this guidance structure, which is going to be an array where each item will have a direction along with some additional props. Right now, the direction member of the individual items is being inferred as a primitive string. Now the challenge that you have in front of you is how can you make direction to be inferred as that type that we declared and leave the inference engine to infer all the other members, for example, distance of type number. The surprising solution comes in the form of the satisfies operator. We want to specify that this particular array should match a

01:05

structure such that the individual items have a direction property of type direction. However, this will actually result in a compiler error. And the reason is the objects contain additional properties in addition to direction. And right now the error is happening on the distance property. We can actually tell TypeScript to include any additional props by creating an intersection with any, however, from the any, we would need to emit the keys for which we have a specific inference. With this new type created, you will see that the direction member of the individual items will be inferred to be of type direction

01:39

and any additional members are left to the default inference engine. For example, distance will be inferred to be of type number. Once you find a pattern that you like, you can actually turn the types that you use for inference into general purpose. Infer utilities. For the use case that we have seen, we can create a general purpose utility called infer props that takes a generic argument T, and then creates a type such that it has tea and includes all of the properties from any except the ones that are keys of tea. And with this utility created or satisfies argument becomes much simpler.

02:12

It is simply infer props such that direction should be of type direction and leave everything else to the default engine. And we can make sure that the things are working as expected. Because when we hover over the individual direction items, you can see that they are inferred to be of type direction.