[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)