Skip to content

Displayed parameter types when invoking a union of functions are inconsistent with behaviorΒ #55574

@ssalbdivad

Description

@ssalbdivad

πŸ”Ž Search Terms

function parameter display signature helper inconsistent union

πŸ•— Version & Regression Information

This is the behavior in every version I tried

⏯ Playground Link

https://www.typescriptlang.org/play?ssl=27&ssc=1&pln=1&pc=1#code/CYUwxgNghgTiAEYD2A7AzgF3kgDhglqlBGgFwBQ8V8APvABT1QD8p8A3vFGxjAK4IAvgEp4AXgB88PigDWKJAHcUwytTqMARqw7xNPfkNGTpchctXlQkWAmTosuAkQgARfGhzQAnm3pqqWABzAAY-Tm54XgF4QXgAMl19KMNY0ToZUAAzfBQQYHJjKRl5JRRycgB6SvgAFQALD3g0fCCUKAw+OHgQGBgkGDR4RXqQFHgFLBwoNDR8rnHg8idCdrcPLyhvektq+HdPH2bW9s7u+lzkPvAMVT2VlzQmGFDwrgMBAG5YhKSPkG+IlopmyuXywjYJXM5T2ACEQPUoAA3QgwBhXOBgW5VGoPNZPYIhHT0CL-QG-TjJaIAtKQsxlZZ4VbEJ6WazQbr2TDwOCYNgBYGMFhsUkpGKCAA08AAdLLeRg2JgYLkggBtAC6RVMpQsAo09G0Ir0-zS4mK9N1OP2GyOLTaHS6CAuKAxNylk3wYAQ8vgTUmXCxfGIEG8XB5IG5IAgIAAtmNsXtnq8GKLqZ84olKWTTRkUKC8sApfLFbwVRqtSVUMorfDESiBuiBpiEzUk0S3pE0xm-mKaSIpbLpcXmqWUGrNWbtVXyvKSe9e1KqalJfAAERZJBIVdS1eaWCr1RAA

πŸ’» Code

declare const optionals:
    | ((a?: { a: true }) => unknown)
    | ((b?: { b: true }) => unknown)

declare const optionalDisplay: (
    arg0: ({ a: true } & { b: true }) | undefined
) => unknown

// This signature errors when not passed an arg
optionalDisplay()

// Display signature (incorrect)
// optionals(arg0: ({ a: true; } & { b: true; }) | undefined): unknown
// Behavior (correct)
// optionals(arg0?: ({ a: true; } & { b: true; }): unknown
optionals()

declare const rest: 
    | ((a?: { a: true }, ...rest: string[]) => unknown)
    | ((b?: { b: true }) => unknown)

// Display signature (incorrect, notice rest is not actually a rest element)
// (arg0: ({ a: true;} & { b: true; }) | undefined, rest: string[]) => unkonwn
// Behavior (correct)
// (arg0?: ({ a: true;} & { b: true; }), ...rest: string[]) => unkonwn
rest({ a: true, b: true }, "foo", "bar")

πŸ™ Actual behavior

Types are enforced correctly but displayed incorrectly

πŸ™‚ Expected behavior

The actual types enforced should be the same as those displayed.

Additional information about the issue

There are likely many other scenarios where these inconsistencies occur (and there may be cases where the behavior is also incorrect). I was recently working on a utility that required providing parameters to a union of function types like this, and ended up writing a custom intersectParameters generic. I believe this correctly handles all edge cases involving variadic and optional elements (the results for non-trailing variadic elements are suboptimal but I believe that is a result of how TS handles them in general).

This could potentially be useful in adapting a runtime solution to ensure these signatures are displayed correctly, e.g.:

image

https://tsplay.dev/W4VQ4N

I also made a version that was parameterized to handle reducing tuple intersections as well since it's a very related problem- happy to share that if it would be useful.

It would be great if robust logic for these kinds of operations were made available through TS directly in situations like this so that I could avoid maintaining these types going forward!

Metadata

Metadata

Assignees

Labels

BugA bug in TypeScriptDomain: LS: Type DisplayBugs relating to showing types in Quick Info/Tooltips, Signature Help, or Completion InfoFix AvailableA PR has been opened for this issue

Type

No type

Projects

No projects

Relationships

None yet

Development

No branches or pull requests

Issue actions