Skip to content

Inconsistent function argument type inference based on result assignment wayΒ #59781

Closed

Description

@AjiTae

πŸ”Ž Search Terms

assignment, inference

πŸ•— Version & Regression Information

  • This is the behavior in every version I tried, and I reviewed the FAQ for entries about destructuring assignment

⏯ Playground Link

https://www.typescriptlang.org/play/?ts=5.5.4#code/CYUwxgNghgTiAEAzArgOzAFwJYHtVKxgGcMAKAIwC54BGASmppoG4AoUSWBFdbPeIuDzBSUagCYG8ceLbtw0OEjSZc+EAA9wyDCAA8AFXibdqYEXhwowPBACe8NAGtUOAO6oA2gF0AfKR5VPCJqAwAaeGAoDDF4AEEYAHNkAFsQVAwiQ18pACUQDGQYVCyDXzkwYIx4T0RCEnyiZAgMCMFKs0bmjG94AF5jLTAdEFJa+taBITNvCM8aCPFvOmZ4AHo1+BwnVg6SSxAmlosBzW1dMbriSfbhWZqF6WXVjeMYGFC7AAcEAHJUVLkEAwX7wLAWVzVKBEIhYRKoKDkCAIDA4eAYb5-NCgOqoEDAX6sVgYn7wfKFYqlQamcwHay2BzOVweHy+frwADerHgNQA0mD8E4QHYcIh4AZvKFPLzeiZ0rTSAA6ZWwRIheBQVB2Hx0fpsrCoRDAsnwAD8JuoeIAbsC2ABfNgkhAJZJpDJUuVmCxWGyoeyOVAudxePzsrk86UC+BCkViiVSmXU+UWURJagGo0wMm6vpspnBs0W+DW22sB1AA

πŸ’» Code

declare function first(b: 1): 11;
declare function second(a: 2): 22;

declare function execute<T extends readonly unknown[]>(functions: T, data: Arguments<T>): Returns<T>;

const [a, b] = execute([first, second], [1, 2]); // ok

const result = execute([first, second], [1, 2]); // err: Type 'number' is not assignable to type 'undefined'

type Returns<T extends readonly unknown[]> = {
  [K in keyof T]: T[K] extends (...args: any[]) => infer R ? R : never;
};
type Arguments<T extends readonly unknown[]> = {
  [K in keyof T]: T[K] extends (arg: infer R) => unknown ? R : never;
};

πŸ™ Actual behavior

Type inference works differently with destructuring assignment compared to regular assignment.

πŸ™‚ Expected behavior

Type inference shouldn't be affected by assignment way.

Additional information about the issue

I know the types for execute function are not right, but its irrelevant.

Activity

  1. Andarist commented on Aug 28, 2024

    @Andarist
    Contributor

    TS has to decide how to treat your array literal. It doesn't know if its type should be a tuple type or an array type so it uses contextual information to decide this. The binding pattern is such information here and thanks to it it infers/assigns a tuple type to your first argument. The other example has no such information so it defaults to an array type.

    You can fix this by hinting TS that you want tuples here like this:

    declare function execute<T extends readonly unknown[]>(functions: [...T], data: Arguments<T>): Returns<T>;

    There are also other ways to hint this but I find this one to be the most idiomatic one.

  2. AjiTae commented on Aug 28, 2024

    @AjiTae
    Author

    But should it really behave this way? It's incredibly confusing on a deeper, intuitive js level.:)

  3. Andarist commented on Aug 28, 2024

    @Andarist
    Contributor
  4. locked as resolved and limited conversation to collaborators on Oct 22, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions