You may have already heard what type assertion is, but for a better introduction, below I have written a code example with assertion.
const uniqueButton = document.querySelector("#unique-button") as HTMLButtonElement
The type assertion tells TypeScript that the resulting DOM tree element is a button. Without it, TypeScript would know that it is just an HTML element.
For the examples below, let's assume that our User type is
type User = {
name: string;
age: number;
}
and examples of objects:
const user = {
name: "Pawel",
age: 20,
year: 20,
} as User;
This is dynamic type casting, which can lead to errors, but allows redundant properties. More security is provided by static typing, or so-called type declarations.
const newUser: User = {
name: "Coder",
age: 20,
year: 2044,
};
For the above newUser
object, TypeScript immediately informs Object literal may only specify known properties, and year does not exist in type
. Static typing checks and expects all keys of the type to match.
Type assertions are removed at compile time. Therefore, no exception or null will be generated if the type assertion is invalid.
But let's continue the main thread - it's time for satisfies!
You will see an example of how it works below.
type ApiResponse = {
value: string | null
}
const data2 = {
value: 'success'
} satisfies ApiResponse
data.value.toUpperCase() // SUCCESS
For static typing, the result will end in an error.
const data: ApiResponse = {
value: 'success'
}
data.value.toUpperCase() // 'data.value' is possibly 'null'
A similar problem will arise when the type keys are Union.
type Keys = "name" | "email" | "height" | "address"
const person1: Record<Keys, string | number> = {
name: "Pawel",
email: "coder@example.com",
height: 180.1,
address: "Poland",
}
person1.name.toUpperCase() // Property 'toUpperCase' does not exist on type 'string | number'
person1.height.toFixed() // Property 'toFixed' does not exist on type 'string | number'
const person2 = {
name: "Pawel",
email: "coder@example.com",
height: 180.1,
address: "Poland",
} satisfies Record<Keys, string | number>
person2.name.toUpperCase() // PAWEL
person2.height.toFixed() // 180
Note that with satisfies TypeScript still watches for type incompatibility errors.
person2.name.toFixed()) // Property 'toFixed' does not exist on type 'string'
Satisfies is more flexible than type declaration and safer than assertion. It checks whether an object satisfies all the requirements of the specified type.
So when to use type assertion and satisfies?
Assertions will work well when you want to pass additional information to TypeScript that it doesn't have about the stored object, especially when retrieving DOM elements.
Satisfies will work well when you want the object to retain its type, but you need TypeScript's help to warn you of errors made (as in the example with union).
Go back to Articles