TypeScript 5.4 Highlights: NoInfer, Object.groupBy and Smarter Narrowing

DataFmt Team
#typescript #javascript #tooling #language-features
5 min read

TypeScript 5.4 Highlights: NoInfer, Object.groupBy and Smarter Narrowing

TypeScript 5.4 is a small but very practical release. Here is what actually changes your day-to-day code.

1. NoInfer<T> utility type

You can now mark a generic type parameter as non-inferable, forcing TypeScript to use the explicit annotation:

function createStreetLight<C extends string>(
  colors: C[],
  defaultColor?: NoInfer<C>
) { /* ... */ }

createStreetLight(["red", "yellow", "green"], "red");    // ✅
createStreetLight(["red", "yellow", "green"], "blue");   // ❌ error

Without NoInfer, the compiler would widen C to include "blue". This was a frequent source of subtle bugs in API design.

2. Preserved narrowing in closures after last assignment

Before 5.4, narrowing was lost inside callbacks:

function f(x: string | number) {
  if (typeof x === "string") {
    return () => x.toUpperCase(); // x was widened to string | number
  }
}

Now the compiler tracks that x was last assigned a string and keeps the narrowing inside the closure.

3. Object.groupBy and Map.groupBy

ECMAScript 2024 added Object.groupBy, and TypeScript 5.4 ships the types:

const items = [{ kind: "fruit" }, { kind: "veg" }, { kind: "fruit" }];
const grouped = Object.groupBy(items, (i) => i.kind);
// { fruit: [...], veg: [...] }

4. Take-aways

  • Use NoInfer whenever a generic appears in two argument positions and only one should drive inference.
  • Trust the compiler more inside callbacks — fewer as casts.
  • Replace lodash groupBy with the standard library where you can.

Found this helpful? Try our free tools!

Explore Our Tools →