Satisfying TypeScript: How the 'Satisfies' Keyword Can Simplify Your Code
It is satisfying… Ok, I admit that was a bad pun, but I couldn't resist! In this blog post, I want to discuss how great the satisfies
keyword is for TypeScript and give you an idea of when to use it. This topic was inspired by Matt Pocock. Note that the satisfies
keyword is available in TypeScript version 4.9 and later.
When we define an object with properties, TypeScript can infer the types of those properties.
const dogs = { breed: 'Labrador Retriever', age: 3, favoriteToys: ['squeaky ball', 'rope toy'], size: 'medium' }
If we let TypeScript infer types, we may run into issues such as misspelling a word like breed
as brede
.
One way to avoid this is by using a utility type:
type DogToys = [string, string]; const dogs: Record<'breed' | 'size' | 'age' | 'favoriteToys', string | number | DogToys> = { breed: 'Labrador Retriever', age: 3, favoriteToys: ['squeaky ball', 'rope toy'], size: 'medium' }
Now, if we misspell any word in our properties, TypeScript will alert us!
However, there is still an issue here. Attempting to access a property and convert it to something using a JavaScript method will result in an error.
dogs.size.toUpperCase(); // throws an error
TypeScript doesn't know whether it's supposed to be a string or a number. One way to fix this is by using a conditional statement.
if(typeof dogs.size === 'string) { dogs.size.toUpperCase(); } // TS is happy.
However, this can become an issue as the app grows.
This is where the keyword satisfies
comes in.
type DogToys = [string, string]; const dogs = { breed: 'Labrador Retriever', age: 3, favoriteToys: ['squeaky ball', 'rope toy'], size: 'medium' } satisfies Record<'breed' | 'size' | 'age' | 'favoriteToys', string | number | DogToys>
Now, when we hover over dogs
, we can see the types for each property, and there is no risk of misspelling a word. Additionally, you can remove the conditional statement.
dogs.size.toUpperCase(); // TS is happy!
Let's explore how we can use this in a framework like Next.js.
import { GetServerSideProps, InferGetServerSidePropsType } from 'next' const getServerSideProps: GetServerSideProps = async (ctx) => { return { props: { session: true }, } } type Props = InferGetServerSidePropsType<typeof getServerSideProps>
Our type Props gives us back the following:
type Props = { [key: string]: any; }
By using the satisfies
keyword, we can obtain the actual types of the props, as well as the types of GetServerSideProps
.
const getServerSideProps = (async (ctx) => { return { props: { session: true, db: 'prisma' }, } }) satisfies GetServerSideProps type Props = InferGetServerSidePropsType<typeof getServerSideProps>
And we will receive this type:
type Props = { session: boolean; db: string; }
TADA! I hope these examples help you see the value of using the satisfies
keyword. It can be very satisfying to use!