Skip to content

Instantly share code, notes, and snippets.

@rpivo
Last active December 30, 2022 03:13
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save rpivo/e41b1022666a0d9354e57d247d2d993f to your computer and use it in GitHub Desktop.
Save rpivo/e41b1022666a0d9354e57d247d2d993f to your computer and use it in GitHub Desktop.
Comparing Type Assignment, "as", and "satisfies" in TypeScript

Comparing Type Assignment, "as", and "satisfies" in TypeScript

Say we have two types:

Screen Shot 2022-12-29 at 6 55 10 PM

Using these types, I'll look at the similarities and differences between:

Type Assignment

If we create a new variable and assign it the type Record<Food, Meal>, it will display an error when a key is not the correct type.

Screen Shot 2022-12-29 at 7 00 00 PM

However, because we've assigned the variable to a type which indicates that all values are of type Meal, and because all possible values of type Meal are of type string, then getting the length of any key is okay. The type checker assumes these values are strings at this point. It's basing this assumption on the assigned type for the variable.

Screen Shot 2022-12-29 at 7 02 08 PM

If we expand the type of the values to be Meal | number, then the value for bread is now okay:

Screen Shot 2022-12-29 at 7 05 25 PM

But now, if we try to get the length of any key, the type checker says we can't do this. It's basing this off of the assumed type of the variable, and if the value can be a number, then checking for its length is an error.

Screen Shot 2022-12-29 at 7 07 33 PM

as

Let's remove number from the type once again, and now let's try to cast the variable with as. The type checker sees that the value for bread cannot possibly be Meal since a number is not a string. It doesn't allow this, and it also doesn't provide as much visual specificity in the error. The object cannot possibly match the type, and so the whole object is in error.

Screen Shot 2022-12-29 at 7 10 17 PM

The type checker still assumes that the keys are all of type Meal, nonetheless. It's basing this on the type we've cast the variable as.

Screen Shot 2022-12-29 at 7 13 23 PM

We can get around this by first casting the object as unknown, but this is a bit of a hack. It's like saying, "hey TypeScript, you see this object? Let's not make any assumptions about what type it is. Got it? Okay, now let's cast it as this other type."

Screen Shot 2022-12-29 at 7 14 41 PM

Again, no problem checking the length of keys since the type checker is assuming the keys are all strings.

Screen Shot 2022-12-29 at 7 16 54 PM

As with type assignment, if we widen the type of the values to include number, then we can cast the variable as the type without issue.

Screen Shot 2022-12-29 at 7 17 56 PM

The type checker does the same thing here when checking for the length of the keys. It's assuming the variable has either strings or numbers for keys, and numbers don't have a length.

Screen Shot 2022-12-29 at 7 19 24 PM

One thing to note is that we can reassign bread to a number, and the type checker does not complain about this. That's because the type checker is assuming the values of the object to be either of type Meal or number, so reassigning a value from a string to a number is okay.

Screen Shot 2022-12-29 at 10 03 06 PM

satisfies

Let's once again narrow the type of the values so that they do not include number. As with type assignment and casting with as, saying the variable satisfies the type will show an error. Unlike as, the visual info here is more specific, and we can see the problem key. In this way, type assignment and satisfies are a bit better than as for debugging.

Screen Shot 2022-12-29 at 7 20 46 PM

With satisfies, the type checker does NOT check against all of a value's types. It instead "locks in" the type of the variable at the time of declaration. If the value is a number, then henceforth all type checking against the value will assume it is a number. If the value starts as a string, then it will have access to string methods. If it's not a string, then the type checker will throw an error if a string method is used on it.

Screen Shot 2022-12-29 at 7 23 48 PM

Let's once again widen the type of the values to include number. bread now fits within the type.

Screen Shot 2022-12-29 at 7 26 44 PM

But still, the type checker checks against the actual type of the value at creation time.

Screen Shot 2022-12-29 at 7 29 39 PM

Interestingly, the type checker will not let you reassign the variable from a string to a number because satisfies locks in the type of the value at variable creation.

Screen Shot 2022-12-29 at 10 12 10 PM

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment