TypeScript - Record and the satisfies operator

This post is part of an ongoing series on TypeScript. In it, I try to explain in a detailed way different situations I’ve faced while building relatively big React applications using TypeScript, and moving them from JavaScript. Here’s a list of other posts I’ve written about TypeScript:


In a previous entry I argued that the use of the Record type is dangerous in some circumstances and suggested using a Dictionary type to solve that. The goal of the Dictionary type is to make sure the type of values from property access returns T | undefined as opposed to just T (which would suggest that we have a T for any K in the dictionary).

The release of TypeScript 4.9 includes a new operator called satisfies. It can be used to solve the situation I presented in that other post:

type Breed = string

interface Dog {
  name: string
}

const dogsByBreed: Record<Breed, Dog[]> = {
  akita: [{ name: 'Walter' }, { name: 'Gracie' }],
  dachshund: [{ name: 'Charlie' }],
}

dogsByBreed.poodle // Type is Dog[], value is undefined.

Instead of introducing a Dictionary type, you can now simply do this:

const dogsByBreed = {
  akita: [{ name: 'Walter' }, { name: 'Gracie' }],
  dachshund: [{ name: 'Charlie' }],
} satisfies Record<Breed, Dog[]>

dogsByBreed.poodle // Type error!

TypeScript gives us a static type-check with the message:

Property 'poodle' does not exist on type '{ akita: { name: string; }[]; dachshund: { name: string; }[]; }'.

Which is absolutely correct and gives us the best of both worlds:

I’m happy to be able to update the previous post to link to this one. Until next time!