TIL: `satisfies` is my favorite TypeScript keyword

I’ve been doing a lot of work in TypeScript lately, and with that I’ve spent quite a bit of time learning more about its type system. TypeScript is a wonderfully advanced language though it has an unfortunately steep learning curve; in many ways it’s the complete opposite of Go.

One confusing thing about TypeScript is that it doesn’t always infer the most precise type possible. As an example:

// name is of type "Jerred"
const const name: "Jerred"name = "Jerred";

// person1 is of type { name: string }
const 
const person1: {
    name: string;
}
person1
= {
name: stringname: "Jerred", }; // person2 is of type { readonly name: "Jerred" } const
const person2: {
    readonly name: "Jerred";
}
person2
= {
name: "Jerred"name: "Jerred", } as
type const = {
    readonly name: "Jerred";
}
const
;

Why is the name of person1 of type string and not the literal "Jerred"? Because the object could be mutated to contain any other string.

What happens when I want to pass those objects to a function that requires name to be "Jerred"?

function function handleJerred(name: "Jerred"): voidhandleJerred(name: "Jerred"name: "Jerred") {
  // do something
}

// these are okay
function handleJerred(name: "Jerred"): voidhandleJerred(const name: "Jerred"name);
function handleJerred(name: "Jerred"): voidhandleJerred(
const person2: {
    readonly name: "Jerred";
}
person2
.name: "Jerred"name);
function handleJerred(name: "Jerred"): voidhandleJerred(person1.name);
Argument of type 'string' is not assignable to parameter of type '"Jerred"'.

As we’d expect, the types don’t match up. The most obvious way is to annotate the variable declaration with the expected type:

const 
const person1: {
    name: "Jerred";
}
person1
: { name: "Jerred"name: "Jerred" } = {
name: "Jerred"name: "Jerred", }; // okay function handleJerred(name: "Jerred"): voidhandleJerred(
const person1: {
    name: "Jerred";
}
person1
.name: "Jerred"name);

We could also use the satisfies keyword. This keyword is a bit esoteric and not very common, but it comes in handy in some scenarios where you’d otherwise pull your hair out.

Here’s a quick example just to show the syntax:

const 
const person1: {
    name: "Jerred";
}
person1
= {
name: "Jerred"name: "Jerred", } satisfies { name: "Jerred"name: "Jerred" }; // okay function handleJerred(name: "Jerred"): voidhandleJerred(
const person1: {
    name: "Jerred";
}
person1
.name: "Jerred"name);

satisfies is an alternative to an explicit variable type annotation. It tells TypeScript that your assignment should be at least assignable to the provided type. It’s kind of like a type-safe way to cast values.

The benefit of satifies over an variable type annotation is that it lets TypeScript infer a more specific type based on the value provided. Consider this scenario:

type 
type Person = {
    name: string;
    isCool: boolean;
}
Person
= {
name: stringname: string; isCool: booleanisCool: boolean; }; function
function coolPeopleOnly(person: Person & {
    isCool: true;
}): void
coolPeopleOnly
(
person: Person & {
    isCool: true;
}
person
:
type Person = {
    name: string;
    isCool: boolean;
}
Person
& { isCool: trueisCool: true }) {
// only cool people can enter here } const const person1: Personperson1:
type Person = {
    name: string;
    isCool: boolean;
}
Person
= {
name: stringname: "Jerred", isCool: booleanisCool: true, }; // okay, so we need to say that `isCool` is true
function coolPeopleOnly(person: Person & {
    isCool: true;
}): void
coolPeopleOnly
(person1);
Argument of type 'Person' is not assignable to parameter of type 'Person & { isCool: true; }'. Type 'Person' is not assignable to type '{ isCool: true; }'. Types of property 'isCool' are incompatible. Type 'boolean' is not assignable to type 'true'.
// and we also need to include the name field... const
const person2: {
    isCool: true;
}
person2
: { isCool: trueisCool: true } = {
name: "Jerred",
Object literal may only specify known properties, and 'name' does not exist in type '{ isCool: true; }'.
isCool: trueisCool: true, }; const
const person3: {
    name: string;
    isCool: true;
}
person3
: { name: stringname: string; isCool: trueisCool: true } = {
name: stringname: "Jerred", isCool: trueisCool: true, };
function coolPeopleOnly(person: Person & {
    isCool: true;
}): void
coolPeopleOnly
(
const person3: {
    name: string;
    isCool: true;
}
person3
);

A simpler solution is to use satifies:

const 
const person: {
    name: string;
    isCool: true;
}
person
= {
name: stringname: "Jerred", isCool: booleanisCool: true, } satisfies
type Person = {
    name: string;
    isCool: boolean;
}
Person
;
function coolPeopleOnly(person: Person & {
    isCool: true;
}): void
coolPeopleOnly
(
const person: {
    name: string;
    isCool: true;
}
person
);

TypeScript will ensure that your value is assignable to your type. The type of the assigned variable will be made based on the type of the value instead of the type provided to satisfies.

This really comes in handy when you want to ensure that TypeScript is being as specific as possible.

Read more:

Recent posts from blogs that I like

Great Ladies of Impressionism: Berthe Morisot 1874-1891

Her turning point in 1874 - rejected from the Salon, joining the first Impressionist Exhibition, and marrying Édouard Manet's brother. How those changed art.

via The Eclectic Light Company

AI inference is obviously profitable

Many people claim that AI inference is unprofitable to serve, and thus must be subsidized by an ocean of dumb money from investors who believe that some future AI model will come to dominate the world economy. When that dumb money goes away, so will AI products. According to this view, LLMs are just...

via Sean Goedecke

Escaping Flatland meetups summer 2026: times and places

There has been a flurry of activity in the chat over the last two months, and we now have meetups arranged in 47 cities in 22 countries!

via Henrik Karlsson