Matt Pocock Profile picture
Full-time TypeScript educator. Ex-@vercel, @statelyai. Used to be a voice coach. He/him. Author of Total TypeScript 🧙 Hire me to teach your team TypeScript!

Mar 2, 2023, 18 tweets

satisfies in TypeScript has been out for a little while now.

Overall, it's been a success - but it's starting to cause some confusion.

Let's clear it up.

satisfies has added yet another tool to the TypeScript user's toolkit.

There are now _three_ ways to assign types to values.

First, there's the humble 'colon annotation'.

This concept isn't really given a name in the TS docs, so I'll use this slightly medical name.

This lets you say 'this variable is always this type'.

When you use a colon annotation, you're _declaring_ that the variable is that type.

That means that the thing you assign to the variable _must_ be that type.

This means you can actually give a variable a type that's _wider_ than the one you initially assign.

This is useful when you want to have a default which might later be reassigned.

But colon annotations come with an edge-case downside.

When you use one, the type BEATS the value. That means that if you declare a wider type than you want, you're stuck with the wider type.

In this example, you don't get autocomplete on the routes object.

This is the problem satisfies was designed to solve.

When you use satisfies, the value BEATS the type. This means it infers the narrowest possible type, not the wider type you specify.

satisfies also protects you from specifying the wrong thing inside your config object.

So, colon annotations and satisfies are equally safe.

The third way you can assign types to variables is the 'as' annotation.

Unlike satisfies and colon annotations, 'as' annotations let you lie to TypeScript.

This has some limits - you can add properties to objects, but you can't convert between basic types.

For instance, you can't force TypeScript to convert a string into a number...

...except if you use the monstrous 'as-as'.

Sometimes, 'as' is needed. For instance, when you're converting an object to a known type.

But if you're using 'as' as your default way to annotate variables, that's almost certainly wrong.

The code below might look safe, but as soon as you add another property to the User type, the defaultUser will be out of date - and won't error.

There's actually a secret _fourth_ way to give a type to a variable.

Don't.

TypeScript does an amazing job at inferring types for your variables.

Most of the time, you won't need to type your variables.

So, we've got FOUR ways of assigning a type to a variable.

- colon annotations
- satisfies
- as annotations
- not annotating and inferring it

The mistake I'm seeing a lot of devs make with the release of 'satisfies' is to use it as their new default.

This is fine for simple cases like this:

But most of the time, the times you want to assign a type to a variable are when you _want_ the type to be wider.

For instance, this case. If we used satisfies here, you wouldn't be able to assign numericId to id.

So - satisfies shouldn't be your default. It's for edge cases. It should be for when:

- You want the EXACT type of the variable, not the WIDER type.
- The type is complex enough that you want to make sure you didn't mess it up

If you dug this thread, my TypeScript course just launched - and it's on sale for another week.

Thanks for reading! ❤️❤️

totaltypescript.com

Share this Scrolly Tale with your friends.

A Scrolly Tale is a new way to read Twitter threads with a more visually immersive experience.
Discover more beautiful Scrolly Tales like this.

Keep scrolling