State-of-the-art frontend development
Imagine you're faced with the following problem:
You have a type City that can be either CityName or CityCoordinates:
type City = CityName | CityCoordinates;
CityName is a string representing one of the specified cities:
type CityName = "New York" | "Mumbai" | "Lagos";
CityCoordinates is an object with x and y properties denoting the coordinates of your city:
type CityCoordinates = {
x: number;
y: number;
};
And the User type has birthCity and currentCity, both of which are of type City:
type User = {
birthCity: City;
currentCity: City;
};
Then, you want to create a new variable user that adheres to the User type.
You want to assign "Mumbai" to the birthCity property (that's of the type CityName) and { x: 6, y: 3 } to the currentCity property (that's of the type CityCoordinates).
What you would normally do is something like this π
const user: User = {
birthCity: "Mumbai",
currentCity: { x: 6, y: 3 },
};
That's all well and good and, as of TypeScript 4.8 of less, the only way to make sure that the user variable matches the shape of the User type.
Now, say you want to make the birthCity property of the user variable uppercase.
If you were to do that, however, you'd make TypeScript upset and get an error:
// yields this TypeScript error π
// Property 'toUpperCase' does not exist on type 'City'.
// Property 'toUpperCase' does not exist on type 'CityCoordinates'.
user.birthCity.toUpperCase();
The way that TypeScript sees the birthCity property is that it can be either CityName or CityCoordinates.
It doesn't "know" that you want the user variable to have the CityName type for the birthCity and the CityCoordinates for the currentCity.
satisfies to the rescueBefore the satisfies keyword was introduced, there wasn't a good way to achieve this.
More specifically, it wasn't possible to both
Now that we've got the satisfies keyword, this very thing is now possible!
The syntax is as follows π
const user = {
birthCity: "Mumbai",
currentCity: { x: 6, y: 3 },
} satisfies User
The inferred type of the user variable is going to be π
{
birthCity: "Mumbai";
currentCity: {
x: number;
y: number;
}
}
This will enable us to access string-specific methods (like .toUpperCase()) on the birthCity property and access the x and y number properties on the currentCity variable π
// we can call `toUpperCase`
user.birthCity.toUpperCase();
// ...and we can access the `x` (or `y`) properties
// and call `number`-specific methods on them
user.currentCity.x.toFixed(2);
And, on top of that, if we were to assign a value that doesn't match the User type to the user variable, we would get protected from type errors ππ»
const user = {
// assigning "Beijing" yields this error π
// Type '"Beijing"' is not assignable to type 'City'
birthCity: "Beijing",
currentCity: { x: 6, y: 3 },
} satisfies User
const user = {
name: 'Amy'
} satisfies User
In conclusion, with satisfies we can get the best of both worlds. Type safety saves us from runtime errors and powerful type inference gives us most specific types for free.
You can find the source code for this tutorial on Typescript Playground.
If you liked this tutorial, you can also check out and subscribe to my YouTube channel. Or/and subscribe to my newsletter to get notified when I publish new articles! π
Stay up to date with state-of-the-art frontend development.