Live data from Hacker News

`satisfies` is my favorite TypeScript keyword (2024)

sjer.red

51–60 of 217 posts

Re: `satisfies` is my favorite TypeScript keyword (2024)

#51

> 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…

> 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 [infer First, ...(infer Rest)] ? First extends unknown[] ? [...First, ...FlatArr ] : [First, ...FlatArr ] : []; 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…

The version I was thinking when I wrote the comment is simpler

    type Flatten = T extends Array ? Flatten : T
> The average Typescript dev likely doesn't need to understand recursive conditional types.

The average X dev in Y language doesn't need to understand Z is a poor argument in the context of writing better software.

Re: `satisfies` is my favorite TypeScript keyword (2024)

#52
post #50
post #48

99% of my use of `satisfies` is to type-check exhaustivity in `switch` statements: type Foo = 'foo' | 'bar'; const myFoo: Foo = 'foo'; switch (myFoo) { case 'foo': // do stuff break; default: myFoo satisfies never; // Error here because 'bar' not handled }

Nice. I didn’t know I can now replace my “assertExhaustive” function. Previously you could define a function that accepted never and throws. It tells the compiler that you expect the code path to be exhaustive and fixes any return value expected errors. If the type is changed so that it’s no longer exhaustive it will fail to compile and (still better than satisfies) if an invalid value is passed at runtime it will th…

I thought the same thing. I also have an assert function I pull in everywhere, and this trick seemed like it would be cleaner (especially for one-off scripts to reduce deps).

But unfortunately, using a default clause creates a branching condition that then treats the entire switch block as non-exhaustive, even though it is technically exhaustive over the switch target. It still requires something like throwing an exception, which at that point you might as well do 'const x: never = myFoo'.

Re: `satisfies` is my favorite TypeScript keyword (2024)

#53
post #48

99% of my use of `satisfies` is to type-check exhaustivity in `switch` statements: type Foo = 'foo' | 'bar'; const myFoo: Foo = 'foo'; switch (myFoo) { case 'foo': // do stuff break; default: myFoo satisfies never; // Error here because 'bar' not handled }

https://typescript-eslint.io/rules/switch-exhaustiveness-che... if that is something you're not aware of!

Re: `satisfies` is my favorite TypeScript keyword (2024)

#54

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.

The author gets into that. `Thetype` might be complex. It also protects you from overgeneralizing, like casting to and from `unknown` to escape the type checker.

    type Current = {
      kind: "ac" | "dc";
      amps: number;
    }
    
    type Dc = {
      kind: "dc";
      amps: number;
    }
    
    const ac: Current = {
      kind: "ac",
      amps: 10000000,
    }
    
    const handleDc = (thing: Dc) => {}
    
    const badConvert = (c: Current) => ({...c, kind: "dc"});
    
    /**
    * Argument of type '{ kind: string; amps: number; }' is not assignable to parameter of type 'Dc'.
        Types of property 'kind' are incompatible.
            Type 'string' is not assignable to type '"dc"'.(2345)
    */
    handleDc(badConvert(ac));
    
    const goodConvert = (c: Current) => ({
      ...c, kind: "dc",
    } satisfies Dc);
    
    handleDc(goodConvert(ac));
    
    /**
    * Object literal may only specify known properties, and 'bar' does not exist in type 'Dc'.
    */
    const badConvert2 = (c: Current) => ({
      ...c, kind: "dc", bar: "qwerty"
    } satisfies Dc);

Re: `satisfies` is my favorite TypeScript keyword (2024)

#55
post #24

Earlier quoted context omitted.

If I saw that in a PR I would push very hard to reject; something like that is a maintenance burden that probably isn’t worth the cost, and I’ve been the most hardcore about types and TypeScript of anyone of any team I’ve been on in the past decade or so. Now, that said, I probably would want to be friends with that dev. Unless they had an AI generate it, in which case the sin is doubled.

What's the alternative? Have incorrect types for the function? That's not better.

The alternative is what shows in the comment: go on HN and tell the world you think TS and JS are crap and it's not worth your time, while writing poor software.

Re: `satisfies` is my favorite TypeScript keyword (2024)

#56
post #24

Earlier quoted context omitted.

If I saw that in a PR I would push very hard to reject; something like that is a maintenance burden that probably isn’t worth the cost, and I’ve been the most hardcore about types and TypeScript of anyone of any team I’ve been on in the past decade or so. Now, that said, I probably would want to be friends with that dev. Unless they had an AI generate it, in which case the sin is doubled.

What's the alternative? Have incorrect types for the function? That's not better.

To answer this we probably need more details, otherwise it's gonna be an XY Problem. What is it that I'm trying to do? How would I type this function in, say, SML, which isn't going to allow incorrect types but also doesn't allow these kinds of type gymnastics?

Re: `satisfies` is my favorite TypeScript keyword (2024)

#57
post #6

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.

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 }; I…

Why is satisfies needed at all, when can't. Typescript realize that `a` satisfies `Rect` automatically?

Re: `satisfies` is my favorite TypeScript keyword (2024)

#58

Earlier quoted context omitted.

> 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 [infer First, ...(infer Rest)] ? First extends unknown[] ? [...First, ...FlatArr ] : [First, ...FlatArr ] : []; 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…

The version I was thinking when I wrote the comment is simpler type Flatten = T extends Array ? Flatten : T > The average Typescript dev likely doesn't need to understand recursive conditional types. The average X dev in Y language doesn't need to understand Z is a poor argument in the context of writing better software.

as a person that never touched JS and TS... what's the difference between the two answers?

Re: `satisfies` is my favorite TypeScript keyword (2024)

#59

Earlier quoted context omitted.

> 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 [infer First, ...(infer Rest)] ? First extends unknown[] ? [...First, ...FlatArr ] : [First, ...FlatArr ] : []; 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…

I recently had to write a Promise.all, but using an object instead of an array. That was... non-trivial.

rejoice https://github.com/tc39/proposal-await-dictionary

Re: `satisfies` is my favorite TypeScript keyword (2024)

#60
post #44

So satisfies prevent you from mutating then? Otherwise you could just change name afterwards...

It prevents you from mutating via the reference that you obtain from `satisfies` without casting its type, yes (or rather more precisely, you can mutate it, but only to the one allowed value).

However, the object can still be mutated via other references to it. TypeScript is full of holes like this in the type system - the problem is that they are trying to bolt types and immutability onto a hot mess that is JS data model while preserving backwards compatibility.

Post reply on HN