Skip to content
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

Type parameter inference of function chained parameters and return values does not work. #38872

Closed
WearyMonkey opened this issue Jun 1, 2020 · 4 comments · Fixed by #48538
Closed
Labels
Design Limitation Constraints of the existing architecture prevent this from being fixed Fix Available A PR has been opened for this issue

Comments

@WearyMonkey
Copy link

WearyMonkey commented Jun 1, 2020

I'm writing an API with life cycle methods that are called in a specific order. Each life cycle method can return a 'state' object that is passed to the next life cycle method. I would like the API to be strongly typed, and the type of the state parameters to be inferenced from the return type of the previous life cycle method.

TypeScript Version: 3.9.2, 4.0.0-dev.20200530

Search Terms:

chain inference inference parameter

Code

type Chain<R1, R2> = {
  a(): R1,
  b(a: R1): R2;
  c(b: R2): void;
}

function test<R1, R2>(foo: Chain<R1, R2>) {

}

test({
  a: () => 0,
  b: (a) => 'a',
  c: (b) => {
    const x: string = b; // Type 'unknown' is not assignable to type 'string'.(2322)
  }
});

Expected behavior:

No error.

Actual behavior:

Error 2322 on const x: string = b

Removing the a parameter removes the error and works as expected, e.g.

// ...same as above...

test({
  a: () => 0,
  b: () => 'a',
  c: (b) => {
    const x: string = b; // no error
  }
});

Explicitly providing the parameter type also works, e.g.

// ...same as above...

test({
  a: () => 0,
  b: (a: number) => 'a',
  c: (b) => {
    const x: string = b; // no error
  }
});

Playground Link:

https://www.typescriptlang.org/play?#code/C4TwDgpgBAwgFgQwJYDsA8AlAjAGihgJgD4oBeKAbwCgooEAKASgC59caoAjehV7F-AQDcHAMb1OfAgIBuAeyQATEQF8qVAGYBXFKOBI5KKMAgBnYJlyCi9DXLmt4ydNjyEijSurVUT5+tS0vFBMZCQADDgckiEInqQkAOQIiVG0oqwS8SSBtFCihuZQAB6s5gBOqADmZFwitGoqjCJAA
Related Issues:

@WearyMonkey
Copy link
Author

WearyMonkey commented Jun 1, 2020

Similar issue with a single function consuming its own return type:

type Single<R2> = {
  c(b: R2): R2;
}

function test<R2>(foo: Single<R2>) {

}

test({
  c: (b) => {
    const x: number = b; // Type 'unknown' is not assignable to type 'number'.(2322)
    return 0;
  }
});

https://www.typescriptlang.org/play?#code/C4TwDgpgBAyglgOwOYBsIB4BKAmAfFAXigG8AoKKAYwAoAjALihwEpGcBuUgX1NIDMArgkrA4AewRRgEAM7AseanzFjG8ZGgW5mJXj1LS51MhUqM6OgvhMUqEuVAAejBAIC2tCACdCUWp1soLwhgAS9JAAYAqB4uZk4gA

@noc7c9
Copy link

noc7c9 commented Jun 9, 2020

Facing the same issue.

I also found a possibly related issue: #38845

@RyanCavanaugh RyanCavanaugh added the Needs Investigation This issue needs a team member to investigate its status. label Jun 15, 2020
@RyanCavanaugh
Copy link
Member

@ahejlsberg design limitation or did I miss something?

@ahejlsberg
Copy link
Member

ahejlsberg commented Jun 30, 2020

This is a design limitation. In the original example, the expressions provided for the b and c members are context sensitive. We therefore perform a first phase of type inference where we use wildcard values for those members. In this first phase we successfully infer number for R1, but we make no inferences for R2. We then use our inferences from the first phase to assign types to the contextually typed parameters, and since we have no inferences for R2, the b parameter is given type unknown.

In order to support this particular scenario we'd need additional inference phases, i.e. one per contextually sensitive property value, similar to what we do for multiple contextually sensitive parameters. Not clear that we want to venture there, and it would still be sensitive to the order in which object literal members are written. Ultimately there are limits to what we can do without full unification in type inference.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Design Limitation Constraints of the existing architecture prevent this from being fixed Fix Available A PR has been opened for this issue
Projects
None yet
5 participants