Fundamentals 12 min read

Explore TypeScript 5.4: Closure Type Narrowing, NoInfer, and groupBy

This article examines the new TypeScript 5.4 beta features, including improved type narrowing in closures, the NoInfer utility type for better generic inference, the addition of Object.groupBy and Map.groupBy methods, and several important breaking changes to the type system.

Sohu Tech Products
Sohu Tech Products
Sohu Tech Products
Explore TypeScript 5.4: Closure Type Narrowing, NoInfer, and groupBy

Optimizing Type Narrowing in Closures

TypeScript’s type‑narrowing automatically infers more specific types after checks, but the narrowed type is often lost inside closure callbacks. The article shows examples such as uppercaseStrings and getUrls, where the compiler cannot guarantee that a variable like url remains a URL inside Array.map callbacks. TypeScript 5.4 improves this by tracking the last assignment point for let variables used in non‑hoisted functions, allowing safe narrowing when the final assignment is known. The improvement does not apply when a variable may be reassigned inside nested functions.

function uppercaseStrings(x: string | number) {
  if (typeof x === "string") {
    // TypeScript knows x is a string here
    return x.toUpperCase();
  }
}

function getUrls(url: string | URL, names: string[]) {
  if (typeof url === "string") {
    url = new URL(url);
  }
  return names.map(name => {
    url.searchParams.set("name", name); // error without the new analysis
    return url.toString();
  });
}

Utility Type: NoInfer

When generic functions are called, TypeScript infers the type argument from the provided value. This can sometimes lead to overly permissive or overly restrictive calls, as illustrated by a createStreetLight function that accepts a list of colors and an optional default color. Without constraints, a mismatched default color is accepted. Adding a second generic parameter solves the problem but feels awkward.

TypeScript 5.4 introduces NoInfer<T>, a utility type that tells the compiler not to infer T from a particular argument. Wrapping the default‑color parameter with NoInfer<C> restores the desired strictness without extra generic parameters.

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

createStreetLight(["red", "yellow", "green"], "blue"); // error: "blue" not assignable

Object.groupBy and Map.groupBy

TypeScript 5.4 adds type declarations for the new JavaScript static methods Object.groupBy and Map.groupBy. Object.groupBy groups an iterable into a plain object whose keys map to arrays of the original elements. Map.groupBy does the same but returns a Map, allowing any type of key.

const array = [0, 1, 2, 3, 4, 5];
const obj = Object.groupBy(array, (num) => (num % 2 === 0 ? "even" : "odd"));
// obj = { even: [0,2,4], odd: [1,3,5] }

const map = Map.groupBy(array, (num) => (num % 2 === 0 ? "even" : "odd"));
// map is a Map with the same grouping

When using these methods, the target compiler option must be set to esnext (or the appropriate lib configuration) to make the methods available.

Break Changes

Two notable breaking changes arrive in TypeScript 5.4:

More accurate conditional type constraints . Previously, a conditional type like type IsArray<T> = T extends any[] ? true : false could be resolved based only on the generic constraint, leading to unsound assignments. The new analysis considers all possible instantiations of T, producing a union of outcomes when certainty is lacking.

Stricter intersection handling . Intersections between unrelated types now resolve to never. For example, intersecting a generic T extends "abc" | "def" with a number yields never, and template‑string placeholder checks are more precise.

These changes improve type safety but may require code adjustments where older, more permissive behavior was relied upon.

Reference: https://devblogs.microsoft.com/typescript/announcing-typescript-5-4-beta/

Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

TypeScriptType NarrowingObject.groupByBreak ChangesMap.groupByNoInfer
Sohu Tech Products
Written by

Sohu Tech Products

A knowledge-sharing platform for Sohu's technology products. As a leading Chinese internet brand with media, video, search, and gaming services and over 700 million users, Sohu continuously drives tech innovation and practice. We’ll share practical insights and tech news here.

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.