News for hackers. Stuff that matters.
Re:TypeScript: Control flow analysis for destructured discri... by arxanas on Wednesday November 03, 2021 @04:50PM (#29100088)
Explanation:

A record is a set of key-value pairs with the value having a given type (also called a struct, object, etc. depending on the context). In TypeScript, this is an example of a record:

    const foo = { bar: 1, baz: "qux" };
Destructuring is an ergonomic feature where you can take the fields of a record and assign them to local variables. For example:

    // Equivalent to
    // const bar = foo.bar;
    // const baz = foo.baz;
    const { bar, baz } = foo;
Besides ergonomics, destructuring can offer features like exhaustiveness-checking, to make sure that you used all of the fields of a record.

A union type is a type which denotes that the value is one of two different types, indicated like this:

    type Foo = number | string;
Sometimes, you have two different cases with the same type, and you want to distinguish between them. For example:

    // Not helpful -- we can't tell from the value
    // whether it's supposed to be a username or an email.
    type UsernameOrEmail = string | string;
To handle this case, you can use a discriminated union instead. These unions have a special value which unambiguously indicates which case is present:

    type UsernameOrEmail = { type: "username", value: string }
                         | { type: "email", value: string };
Sometimes, you have a discriminated union with different fields:

    type ApiRequest = { type: "message", subject: string, contents: string }
                    | { type: "view-posts", user_id: number };
Currently, TypeScript uses control-flow analysis to ensure that you're using the right kinds of fields depending on the discriminator value:

    const request: ApiRequest = getRequest();
    if (request.type === "message") {
        // Okay:
        console.log("Subject is", request.subject);
        // Rejected by compiler:
        console.log("User ID is", request.user_id);
    }
However, you can't combine this feature with destructuring:

    type Action = { kind: "A", payload: number }
                | { kind: "B", payload: string };
    
    const { kind, payload } = getAction();
    if (kind === "B") {
        // Not currently allowed:
        payload.toUpperCase();
    }
With this pull request, you can do the above. This can be convenient with patterns like reducers (see https://github.com/microsoft/TypeScript/issues/46143 for an example).
Re:TypeScript: Control flow analysis for destructured discri... by dekerta on Wednesday November 03, 2021 @06:36PM (#29101348)
Thanks for the explanation. I've been programming for many years, and your examples make total sense to me, but reading sentences like "Control flow analysis for destructured discriminated unions" make me feel like a total impostor
Re:TypeScript: Control flow analysis for destructured discri... by codyb on Wednesday November 03, 2021 @11:27PM (#29103405)
It’s just like any other programming problem, break it into parts, and build it back up again.

“What’s a union?”

“Okay… then what’s a discriminated union?”

“Okay… let’s apply destructuring to one…”

“Okay… now what would analysis look like there given what I know?”

“Okay… how do we have the computer know what I know intuitively as a human given this context?”

“Okay! I think I got it!”

:-). If you’ve gotten this far with programming to understand the examples above, my guess is if you just take the time you can do it without the examples if you take it in small enough chunks :-).

Life’s all about what you apply your energy too

(And also, wonderful example :-) )

Re:TypeScript: Control flow analysis for destructured discri... by debaserab2 on Thursday November 04, 2021 @12:32AM (#29103693)
I know you're entirely right, but sometimes when I see things like this in Typescript...

https://github.com/sindresorhus/type-fest/blob/main/source/r...

I can walk through it with enough pause, but it kinda makes my head implode when I glance at it.

Re:TypeScript: Control flow analysis for destructured discri... by JZumun on Thursday November 04, 2021 @05:16AM (#29104912)

  { [Key in KeysType]-?: ... }
TIL that you can disable ? and readonly in mapped types using -. So in the above code, every Key will be mandatory (-?) even if the original one in KeysType was optional.

source: https://www.typescriptlang.org/docs/handbook/2/mapped-types....

Re:TypeScript: Control flow analysis for destructured discri... by codyb on Thursday November 04, 2021 @09:12AM (#29106732)
Yea it’s like reading Shakespeare… I can read the words and know what most of them mean… but damn if it doesn’t take serious energy to actually parse out the meaning sometimes.

I guess in a way, the issue is that it is cloaked with familiarity. Your brain gets so used to understanding sentences on first go it’s not used to not understanding it.

However, if it was a chemistry equation and you weren’t familiar with chemistry it would immediately understand that comprehension would take time and thus the mind implosion due to a lack of understanding doesn’t occur.

Re:TypeScript: Control flow analysis for destructured discri... by dgritsko on Wednesday November 03, 2021 @10:04PM (#29102900)
I think most of us would feel like impostors next to Anders Hejlsberg.
Re:TypeScript: Control flow analysis for destructured discri... by coolgoose on Wednesday November 03, 2021 @06:38PM (#29101369)
You and me both buddy, you and me.
Re:TypeScript: Control flow analysis for destructured discri... by friedman23 on Wednesday November 03, 2021 @05:17PM (#29100387)
Thank you for the explanation, very clear and concise.
Re:TypeScript: Control flow analysis for destructured discri... by Zababa on Wednesday November 03, 2021 @09:47PM (#29102797)
That's a great explanation, thank you for that.
Re:TypeScript: Control flow analysis for destructured discri... by jb_s on Wednesday November 03, 2021 @08:28PM (#29102330)
Union types seem a bit wacky, are they typically used over function overloading or generics?
Re:TypeScript: Control flow analysis for destructured discri... by Zababa on Wednesday November 03, 2021 @09:57PM (#29102851)
An example of union types: many API in JS accept HTTP verbs as strings. With union types, you can say something like:

    type HttpVerb = "GET" | "POST" | "PUT" | "DELETE";
But you can also do more complex stuff:

    type User = {name: string; password: strings} | OAuthID;
By themselves they aren't hard to understand or use.

As an aside, compared to sum types, you don't have to define them before using them: a function can return number | null while in language with sum types you usually define option first and then return option<number>.

Re:TypeScript: Control flow analysis for destructured discri... by arxanas on Wednesday November 03, 2021 @10:23PM (#29103026)
You might find my blog post on some of the uses interesting: https://blog.waleedkhan.name/union-vs-sum-types/

In a language like TypeScript, they can be used for function overloading since there is no runtime dispatch based on argument type. But usually they're used as sum types in the same way as e.g. Rust enums.

Typescript supports so-called "singleton types", in which a given type is inhabited by exactly one value. This lets you do things like specify not just `string` but specific values like `"foo" | "bar"` as a type. In these cases, I often use them in combination with Typescript's "mapped types", which let you index into a map with a certain type and get another type out. This can be useful for things like RPC calls, where the type of the output depends on the type of the input.

Re:TypeScript: Control flow analysis for destructured discri... by jb_s on Friday November 05, 2021 @04:47AM (#29116818)
>since there is no runtime dispatch based on argument type

Ah, this answers my question I guess. Thanks for the info. I'm about to start a new job doing Typescript stuff so I am going to be deep diving into the language to get my head around it, so this helps a lot :-)

Re:TypeScript: Control flow analysis for destructured discri... by AgentME on Wednesday November 03, 2021 @09:45PM (#29102789)
Union types let you accomplish very similar things to what you can do in languages that support Enums with associated values, like Rust. (See https://doc.rust-lang.org/book/ch06-01-defining-an-enum.html for examples of what that looks like. There's no great direct comparison in Java, because Java Enums don't support associated values like this; the closest Java pattern would involve making multiple classes that each extend an interface or abstract class.)
Re:TypeScript: Control flow analysis for destructured discri... by exdsq on Wednesday November 03, 2021 @09:33PM (#29102721)
The most common thing to use them for in TS is to acknowledge a value could be of type null or undefined. Let’s you then check you’re handling them correctly.