Skip to content

Function inference fails when a final argument is supplied after rest via destructured tuples #43122

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
poteat opened this issue Mar 7, 2021 · 2 comments · Fixed by #53036
Closed
Assignees
Labels
Fix Available A PR has been opened for this issue Needs Investigation This issue needs a team member to investigate its status. Rescheduled This issue was previously scheduled to an earlier milestone

Comments

@poteat
Copy link

poteat commented Mar 7, 2021

Bug Report

I'm not sure whether inference failures are usually classified as suggestions or bugs. Sorry if I've assigned this the wrong label!

📖 Context / Introduction

I'm trying to improve the typings for an open source library called reselect. Their createSelector function first takes in an arbitrary amount of "selector" functions that take in one parameter as a given state type, and then takes in one final additional function which combines the results of the previous functions. I have an implementation, but inference isn't working as I expect.

⏯ Playground Link

Playground link with relevant code

💻 Code

export type Selector<State> = (state: State) => unknown;
export type SelectorTuple<State> = Selector<State>[];

export type ExampleState = {
  foo: "foo";
  bar: 42;
};

export function createSelector<S extends SelectorTuple<ExampleState>>(
  ...selectors: [...selectors: S, f: (x: any) => any] // f causes issues
) {
  console.log(selectors);
}

createSelector(
  (x) => x.foo, // x is of 'any' type rather than ExampleState
  (x) => x.bar, // x is of 'any' type rather than ExampleState
  () => 42
);

🙁 Actual behavior

In the createSelector call, all of the x parameters have an implicit type of any, instead of ExampleState.

Observations:

  • When the last tuple element is removed from the type, inference works.
  • When the last tuple element is made to have zero parameters, inference works.
  • When the last tuple element is made to be anything except a function or any, inference works.

For some reason, the compiler is having difficulty inferring the rest parameters in this case.

🙂 Expected behavior

I would expect the type system to infer that the x parameter of all functions except the last is ExampleState.

@mkantor
Copy link
Contributor

mkantor commented Mar 7, 2021

In case it's useful, here's a smaller example of the same issue:

declare function example(...args: [...((n: number) => void)[], (x: any) => void]): void
example(
  x => x.foo, // x is any rather than number
  x => x.bar, // x is any rather than number
  x => x.baz, // x is correctly any here, but noImplicitAny is incorrectly complaining
)

Playground

@RyanCavanaugh RyanCavanaugh added the Needs Investigation This issue needs a team member to investigate its status. label Mar 8, 2021
@RyanCavanaugh RyanCavanaugh added this to the TypeScript 4.3.1 milestone Mar 8, 2021
@RyanCavanaugh RyanCavanaugh added the Rescheduled This issue was previously scheduled to an earlier milestone label Jun 18, 2021
@JensDll
Copy link

JensDll commented Oct 22, 2021

I'm seeing a similar problem at the moment where the parameter type of functions inside of tuples are implicit any. This might not be completely related but it seems similar:

type A = (a: number) => number
type B = (b: string) => string

type T = [A, number] | [B, string]

const t1: T = [x => x, 42] // x is any rather than number
const t2: T = [x => x, ''] // x is any rather than string

Playground

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Fix Available A PR has been opened for this issue Needs Investigation This issue needs a team member to investigate its status. Rescheduled This issue was previously scheduled to an earlier milestone
Projects
None yet
Development

Successfully merging a pull request may close this issue.

7 participants