Skip to content

Default rest parameter names to destructuring names when of an anonymous tupleΒ #56289

Closed
@JoshuaKGoldberg

Description

@JoshuaKGoldberg

πŸ” Search Terms

default rest parameter name destructure anonymous tuple

βœ… Viability Checklist

  • This wouldn't be a breaking change in existing TypeScript/JavaScript code
  • This wouldn't change the runtime behavior of existing JavaScript code
  • This could be implemented without emitting different JS based on the types of the expressions
  • This isn't a runtime feature (e.g. library functionality, non-ECMAScript syntax with JavaScript output, new syntax sugar for JS, etc.)
  • This feature would agree with the rest of our Design Goals: https://github.com/Microsoft/TypeScript/wiki/TypeScript-Design-Goals

⭐ Suggestion

Right now, when calling a function with an inline destructured rest parameter whose type is an anonymous tuple, the inferred variable names will be auto-generated like __0_0:

function withPair(...[first, second]: [number, named: string]) { }

withPair(/* __0_0: number, named: string */ 0, "");

In cases where the tuple is destructured inline, how about any constant/static destructuring names being used as a fallback for anonymous tuple elements?

I.e.:

function withPair(...[first, second]: [number, named: string]) { }

withPair(/* first: number, named: string */ 0, "");

πŸ“ƒ Motivating Example

The pattern of immediately destructured rest parameters of a tuple is one that sometimes gets used for better type safety on parameters than generics or overloads. One downside, though, is that developers have to either explicitly add names to the tuple type or suffer from poor auto-generated parameter hints.

A slightly more real-world example:

interface AppleInfo {
  color: "green" | "red";
}

interface BananaInfo {
  curvature: number;
}

type FruitAndInfo = ["apple", AppleInfo] | ["banana", BananaInfo];

function logFruitTuple(...[fruit, info]: FruitAndInfo) {
  switch (fruit) {
    case "apple":
      console.log(`My apple's color is ${info.color}.`);
      break;
    case "banana":
      console.log(`My banana's curvature is ${info.curvature}.`);
      break;
  }
}

logFruitTuple(/* __0_0: "apple", __0_1: AppleInfo */ "apple", { color: "red" });

With this suggested change, the parameter hints for logFruitTuple would instead be:

logFruitTuple(/* fruit: "apple", info: AppleInfo */ "apple", { color: "red" });

πŸ’» Use Cases

This pattern of destructuring rest parameters of a tuple type allows for precise descriptions of type parameters. It can sometimes be preferable for types over:

  • Function overloads: which allow for descriptions of different call signatures for a function, but the function's body doesn't apply type narrowing based on them (function overloads playground)
  • Generic functions: which also can't always type narrow internally (generic function playground)

Thanks to @evangalen for noting this in https://twitter.com/EmilVanGalen/status/1719622053769216013!

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions