[HN Gopher] TIL: `satisfies` is my favorite TypeScript keyword
       ___________________________________________________________________
        
       TIL: `satisfies` is my favorite TypeScript keyword
        
       Author : surprisetalk
       Score  : 47 points
       Date   : 2025-11-18 16:23 UTC (4 days ago)
        
 (HTM) web link (sjer.red)
 (TXT) w3m dump (sjer.red)
        
       | jonny_eh wrote:
       | > 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.
       | 
       | Typescript in a nutshell. That said, satisfies is a good keyword!
        
       | epolanski wrote:
       | > TypeScript is a wonderfully advanced language though it has an
       | unfortunately steep learning curve
       | 
       | An extremely steep one.
       | 
       | The average multi-year TypeScript developer I meet can barely
       | write a basic utility type, let alone has any general (non
       | TypeScript related) notion of cardinality or sub typing. Hell,
       | ask someone to write a signature for array flat, you'd be
       | surprised how many would fail.
       | 
       | Too many really stop at the very basics.
       | 
       | And even though I consider myself okay at TypeScript, the gap
       | with the more skilled of my colleagues is still impressively
       | huge.
       | 
       | I think there's a dual problem, on one side type-level
       | programming isn't taken seriously by the average dev, and is
       | generally not nurtured.
       | 
       | On the other hand, the amount of ideas, theory, and even worse
       | implementation details of the TypeScript compiler are far from
       | negligible.
       | 
       | Oh, and it really doesn't help that TypeScript is insanely
       | verbose, this can easily balloon when your signatures have
       | multiple type dependencies (think composing functions that can
       | have different outputs and different failures).
        
         | undeveloper wrote:
         | these are things most developers don't know how to do in most
         | language's type systems. I think only rust with its focus on
         | functional roots has seen similar focus on utilizing its type
         | system to its fullest extent.
        
         | lloydatkinson wrote:
         | TypeScript codebases I've seen generally seem to have the
         | widest demonstration of skill gap versus other languages I use.
         | 
         | For example, I don't ever see anyone using `dynamic` or
         | `object` in C#, but I will often see less skilled developers
         | using `any` and `// @ts-ignore` in TypeScript at every possible
         | opportunity even if it's making their development experience
         | categorically worse.
         | 
         | For these developers, the `type` keyword is totally unknown.
         | They don't know how to make a type, or what `Omit` is, or how
         | to extend a type. Hell, they usually don't even know what a
         | union is. Or generics.
         | 
         | I sometimes think that in trying to just be a superset of
         | JavaScript, and it being constantly advertised as so,
         | TypeScript does not/did not get taken seriously enough as a
         | standalone language because it's far too simple to just slot
         | sloppy JavaScript into TypeScript. TypeScript seems a lot
         | better now of having a more sane tsconfig.json, but it still
         | isn't strict enough by default.
         | 
         | This is a strong contrast with other languages that compile to
         | JavaScript, like https://rescript-lang.org/ which has an
         | example of pattern matching right there on the home page.
         | 
         | Which brings me onto another aspect I don't really like about
         | TypeScript; it's constantly own-goaling itself because of it's
         | "we don't add anything except syntax and types" philosophy. I
         | don't think TypeScript will ever get pattern matching as a
         | result, which is absurd, because it has unions.
        
         | ForHackernews wrote:
         | Honestly I just use TypeScript to prevent `1 + [] == "1"` and
         | check that functions are called with arguments. I don't care
         | about type theory at all and the whole thing strikes me as
         | programmers larping (poorly) as mathematicians.
        
           | epolanski wrote:
           | I couldn't care less about mathematics, but I do care about
           | making impossible state impossible and types documenting the
           | domain.
           | 
           | If you type some state as:                   isLoading:
           | boolean         result: Foo         hasError: boolean
           | errorMessage: string | null
           | 
           | then you're creating a giant mess of a soup where the state
           | of your program could have a result, be loading and an error
           | at the same time. If you could recognise that the state of
           | your program is a sum of possible states (loading | success |
           | error), and not their product as the type above you could
           | highly simplify your code, add more invariants and reduce the
           | number of bugs.
           | 
           | And that is a very simple and basic example, you can go
           | *much* further, as in encoding that some type isn't merely a
           | number through branded types, but a special type of number,
           | be it a positive number between 2 and 200 or, being $ or
           | celsius and avoiding again and entire class of bugs by
           | treating everybody just as an integer or float.
        
         | samdoesnothing wrote:
         | I have mixed feelings about Typescript, I hate reading code
         | with heavy TS annotations because JS formatters are designed to
         | keep line widths short, so you end up with a confusing mess of
         | line breaks. Pure JS is also just more readable.
         | 
         | Also you can so easily go overboard with TS and design all
         | sorts of crazy types and abstractions based on those types that
         | become a net negative in your codebase.
         | 
         | However it does feel really damn nice to have it catch errors
         | and give you great autocomplete and refactoring tooling.
        
         | afavour wrote:
         | > Too many really stop at the very basics.
         | 
         | I don't think that means it has a steep learning curve. It just
         | means the basics suffice for a ton of TypeScript deployments.
         | Which I personally don't see as the end of the world.
        
           | vosper wrote:
           | Yes, to me this is a biggest feature of Typescript: A little
           | goes a long way, while the advanced features make really cool
           | things possible. I tend to think of there being two kinds of
           | Typescript - Application Typescript (aka The Basics, `type`,
           | `interface`, `Record`, unions etc...) and Library Typescript
           | which is the stuff that eg Zod or Prisma does to give the
           | Application Typescript users awesome features.
           | 
           | While I aspire to Library TS levels of skill, I am really
           | only a bit past App TS myself.
           | 
           | On that note I've been meaning to the the Type-Level
           | Typescript course [0]. Has anyone taken it?
           | 
           | https://type-level-typescript.com/
        
         | pcthrowaway wrote:
         | > Hell, ask someone to write a signature for array flat, you'd
         | be surprised how many would fail.
         | 
         | To be clear, an array flat type:                   type
         | FlatArr<Arg extends unknown[]> = Arg extends [infer First,
         | ...(infer Rest)] ?           First extends unknown[] ?
         | [...First, ...FlatArr<Rest>] :             [First,
         | ...FlatArr<Rest>] :           [];
         | 
         | is far from basic Typescript. The average Typescript dev likely
         | doesn't need to understand recursive conditional types. It's a
         | level of typescript one typically only needs for library
         | development.
         | 
         | Not only have I never been expected to write something like
         | this for actual work, I'm not sure it's been useful when I
         | have, since most of my colleagues consider something like this
         | nerd sniping and avoid touching/using such utilities, even with
         | documentation.
        
       | yieldcrv wrote:
       | the cool thing about Typescript is that you never have to know
       | any of this to deliver highly performant enterprise scale
       | software
        
         | michaelcampbell wrote:
         | You can do that with assembly and not know ANY high level
         | language.
         | 
         | You might be interested in reading PG's treatise on "the blub
         | paradox".
        
       | ptrl600 wrote:
       | This is wordier than just "as const", what advantage does it
       | give? (I am a newbie and genuinely don't know)
       | 
       | edit: perhaps the advantage only comes into play for mutable
       | values, where you want a narrower type than default, but not
       | _that_ narrow. Indeed, this is covered in the article, but CTRL+F
       | "as const" doesn't work on the page for whatever reason, so I
       | missed it.
        
         | iddan wrote:
         | With as const you can't verify against another interface
        
         | bastawhiz wrote:
         | I've really only found benefit on the return type of functions,
         | when you can say that a type parameter satisfies a type (with
         | the return type being a boolean). This let's you use `if
         | (isPerson(foo))` and typescript will narrow the type
         | appropriately in the conditional
        
         | reissbaker wrote:
         | The satisfies keyword is quite different than "as const." What
         | it does is:
         | 
         | 1. Enforce that a value adheres to a specific type
         | 
         | 2. But, doesn't cause the value to be cast to that type.
         | 
         | For example, if you have a Rect type like:
         | type Rect = { w: number, h: number }
         | 
         | You might want to enforce that some value satisfies Rect
         | properties... But also allow it to have others. For example:
         | const a = { x: 0, y: 0, w: 5, h: 5 };
         | 
         | If you wrote it as:                   const a: Rect = // ...
         | 
         | TypeScript wouldn't allow you to also give it x and y
         | properties. And if you did:                   as Rect
         | 
         | at the end of the line, TypeScript would _allow_ the x, y
         | properties, but would immediately lose track of them and not
         | allow you to use them later, because you cast it to the Rect
         | type which lacks those properties. You could write an extra
         | utility type:                   type Location = { x: number, y:
         | number };         const a: Location & Rect = // ...
         | 
         | But that can get quite verbose as you add more fields. And
         | besides: in this example, all we actually are trying to enforce
         | is that the object is a Rect -- why do we also have to enforce
         | other things at the same time? Usually TS allows type inference
         | for fields, but here, as soon as you start trying to enforce
         | one kind of shape, suddenly type inference breaks for every
         | other field.
         | 
         | The satisfies keyword does what you want in this case: it
         | enforces the object conforms to the type, without casting it to
         | the type.                   const a = { x: 0, y: 0, w: 5, h: 5
         | } satisfies Rect;         // a.x works
         | 
         | Then if someone edits the code to:                   const a =
         | { x: 0, y: 0, width: 5, height: 5 } satisfies Rect;
         | 
         | TypeScript will throw an error, since it no longer satisfies
         | the Rect type (which wants h and w, not height and width).
        
           | michaelcampbell wrote:
           | Thanks; succinct and for me, I understood it.
        
       | Waterluvian wrote:
       | I'm so frustrated by satisfies because it eliminates optional
       | properties.
       | 
       | I want an object of 'LayerConfig' elements where each key is the
       | name of a possible layer. Without 'satisfies' I have to name
       | every layer twice in my config. But with it, I can't have
       | optional properties (eg. Half the layers are fine with the
       | default values for some properties).
       | 
       | The best I've found is a hack that uses a function. But this
       | whole thing where my key literals widen into "string" is a
       | constant annoyance to otherwise very elegant code.
        
         | iddan wrote:
         | Then either make the properties optional or use Partial on the
         | type you are satisfying
        
       | theogravity wrote:
       | The second example confuses me. The Person type has isCool:
       | boolean, not an explicit true. How does using satisfies here pass
       | coolPeopleOnly?
        
         | auxiliarymoose wrote:
         | You can sorta think of `satisfies Foo` as "the type is exactly
         | the literal value, but also make sure the value could be used
         | in the place of a Foo"
        
       | nrhrjrjrjtntbt wrote:
       | Why? why make your code so complex you even hit this problem.
       | Just use the type:
       | 
       | const x: Thetype = ....
       | 
       | I am not keen on as const either. Just program to interfaces. It
       | is a better way to think IMO.
        
       ___________________________________________________________________
       (page generated 2025-11-22 23:00 UTC)