1. 9
    1. 4

      the amount of times I have written map, forEach, or even just regular old for loops to group objects together makes the implementation of Object.groupBy very welcome.

      1. 3

        I’ve just kept on reaching for Lodash’s groupBy in those situations. It’s nice to see another useful Lodash (or underscore?) feature being adopted by the language.

      2. 2
        function createStreetLight<C extends string>(colors: C[], defaultColor?: C) {
            // ...
        }
        createStreetLight(["red", "yellow", "green"], "blue");
        

        In this call, type inference decided that “blue” was just as valid of a type as “red” or “yellow” or “green”. So instead of rejecting the call, TypeScript infers the type of C as “red” | “yellow” | “green” | “blue”.

        I would call that a bug, based on the principle of least surprise. Maybe it’s too late, but NoInfer seems like a workaround.

        1. 2

          Are you saying you expect it to infer only from the first argument (rather than only from the second, and decide the type is “blue”) because it’s the leftmost use of C? I would find that more surprising since I expect to be able to reorder a function’s arguments (and all call sites) without it breaking anything.

          1. 2

            Yeah I would either expect to infer from the first argument, or from the array - if I’ve said one argument is C[] and the other is C then I think it should error on C not being a member of C[] regardless of what the order of arguments is.

            I see your point though, and also I can see why it works the way it does. If I really want to tell a function “this is the limited set of colours you can accept” then I probably want to use an enum or string union, not C extends string

            So I’ll back off saying it should be a bug - though I still find it surprising on first glance.

            1. 1

              In general TypeScript will infer the most generous thing to make an expression work. Basically if any possible valid passes the type check the expression will be considered valid. So in this case inferring C as string causes the call to pass so it happily does that.

              This inference can be pretty dangerous at times. I wrote a blog post about an example and some possible mitigations a while ago: https://kevincox.ca/2023/07/17/typescript-unconstrained-generic/. I guess I’ll need to do some testing and update the post for the new release.

        2. 2

          The preserved narrowing is a godsent.