Made in Builder

Made in Builder.io

Live Demo 👉 All Demo, No Pitch: Content & Commerce / Builder.io & Elastic Path on 12/13

×

Developers

Product

Use Cases

Pricing

Developers

Resources

Company

Get StartedLogin

Product

Features

Integrations

Talk to an Expert

Pricing

Blog

Home

Resources

Blog

Forum

Github

Login

Signup

×

Visual CMS

Drag-and-drop visual editor and headless CMS for any tech stack

Theme Studio for Shopify

Build and optimize your Shopify-hosted storefront, no coding required

Resources

Blog

Get StartedLogin

‹ Back to blog

typescript

Better Configuration in TypeScript with the `satisfies` Operator

January 17, 2023

Written By Steve Sewell

There's a new and better way to do type-safe configuration in TypeScript.

It is with the new satisfies operator, released in TypeScript 4.9:

Why we need satisfies

Let’s start by rewriting the above example with a standard type declaration.

Everything looks fine so far. We get proper type checking and completion in our IDE.

But, when we go to use the routes object, the compiler (and subsequently our IDE as well) has no idea what the actual configured routes are.

For instance, this compiles just fine, yet would throw errors at runtime:

Why is this? It’s because our Routes type can take any string as a key. So TypeScript approves of any key access, including everything from simple typos to completely nonsense keys. We also get no help in our IDE to autocomplete the valid route keys as well.

You could say “well what about the as keyword”. So why not, we can briefly explore that too:

This is a common practice in TypeScript, but is actually quite dangerous.

Not only do we have the same issues as above, but you can actually write completely nonexistent key and value pairs and TypeScript will look the other way:

Broadly speaking, try to avoid using the as keyword in TypeScript in general.

Satisfies saves the day

Now, we can finally rewrite our above examples with the new satisfies keyword:

With this, we get all of the proper type checking we desire:

And, of course, autocomplete in our IDE:

Screenshot showing your IDE auto completing the `AUTH` property onto `routes.`

We can even take a slightly more complex example, like this:

And now we get IDE autocomplete and type checking all the way down the tree, precisely to how we have configured things, as opposed to based on the more general type we used:

Exactly what we wanted.

Combining with as const

One last situation you may run into is that with just a plain usage of satisfies , our configuration object is captured a little more loosely than might be ideal.

For instance, with this code:

If we check the type of the path property, we get the type string

But when it comes to configuration, this is where const assertions (aka as const) have really shined. If we instead used as const here, we would get more precise types, down to the exact string literal '/':

This may seem like “ok, that’s a neat trick but why do I care”, but let’s consider if we had a method like this that was type-safe all the way down to the exact paths it accepts:

If we just used satisfies, where each path is only known to be a string, we would get type errors here:

Argh! HOME.path is a valid string ('/'), but TypeScript is saying it’s not.

Well, that’s where we can get the best of all worlds by combining satisfies and as const like so:

Now, we have a great solution, with type checking all the way down to the exact literal values we used. Beautiful.

So finally, you might ask, why not just use as const instead of satisfies?

Well, with just as const, we won’t get any type checking of our object itself at the time of authoring it. So that means no autocomplete in our IDE or warnings for typos and other issues at the time of writing.

This is why the combination here is so effective.

Coming to libraries and frameworks near you

The biggest benefit you’ll likely get from this new operator is support in popular libraries and frameworks that you use.

For instance, with NextJS, if you previously wrote:

props in this case is just { [key: string]: any }. Sigh, not very helpful.

But with satisfies, you can instead write:

And with this you get all of the same type checking and completion that you did before, but now the proper props type { hello: string }

Conclusion

Typescript 4.9 introduced the new satisfies keyword, which is extremely handy for most configuration-related tasks in TypeScript.

Compared to a standard type declaration, it can strike an elegant balance between type checking and understanding the exact details of your configuration for optimal type safety and a great in-IDE.

Thank you to u/sauland for proposing this routes example, as well as to Matt Pocock and Lee Robinson for the NextJS example.

About me

Hi! I'm Steve, CEO of Builder.io.

We make a way to drag + drop with your components to create pages and other CMS content on your site or app, visually.

You can read more about how this can improve your workflow here.

You may find it interesting or useful:

Visually build with your components

Builder.io is a Visual CMS that let's you drag and drop to create content on your site visually, using your components.

Stop drowning in a backlog of requests - build with your whole team instead.

Try it out
Learn more

Share

Twitter
LinkedIn
Facebook

Continue Reading
Web Performance14 MIN
Optimal Images in HTML
WRITTEN BYSteve Sewell
January 26, 2023
web development9 MIN
The Tailwind CSS Drama Your Users Don't Care About
WRITTEN BYYoav Ganbar
January 25, 2023
Web Development9 MIN
Fast and Light Relative Time Strings in JS
WRITTEN BYSteve Sewell
January 24, 2023

Product

Visual CMS

Theme Studio for Shopify

Sign up

Login

Featured Integrations

React

Angular

Next.js

Gatsby

Get In Touch

Chat With Us

Twitter

Linkedin

Careers

© 2020 Builder.io, Inc.

Security

Privacy Policy

Terms of Service

Visually build and optimize digital experiences on any tech stack. No coding required, and developer approved.

Sign up

Log in

DEVELOPERS

Builder for Developers

Developer Docs

Github

JSX Lite

Qwik

INTEGRATIONS

React

Angular

Next.js

Gatsby

PRODUCT

Product features

Pricing

RESOURCES

User Guides

Blog

Forum

Templates

COMPANY

About

Careers 🚀

Visually build and optimize digital experiences on any tech stack. No coding required, and developer approved.
Get Started
Log in

DEVELOPERS

Builder for Developers

Developer Docs

Open Source Projects

Performance Insights

PRODUCT

Features

Pricing

RESOURCES

User Guides

Blog

Community Forum

Templates

Partners

Submit an Idea

INTEGRATIONS

React

Next.js

Gatsby

Angular

Vue

Nuxt

Hydrogen

Salesforce

Shopify

All Integrations

Security

Privacy Policy

Terms of Service

By clicking “Subscribe”, I agree to Builder.io's Terms of Service and Privacy Policy.