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

Generic return type inferred only with explicitly typed (not inferred) parameter #31892

Closed
Diniden opened this issue Jun 13, 2019 · 2 comments
Closed
Labels
Design Limitation Constraints of the existing architecture prevent this from being fixed

Comments

@Diniden
Copy link

Diniden commented Jun 13, 2019

TypeScript Version: 3.6.0-dev.20190613, 3.5.1

Search Terms: Generic Inferred Return Type

Code

This is an example of the inferred return type being unknown

type TestType = {};

interface ITest<TProperty, TReturn> {
  option: TProperty;
  test(val: TProperty): TReturn;
  check(val: TReturn): void;
}

class ClassTest<TProperty, TReturn> {
  constructor(_o: ITest<TProperty, TReturn>) {
    // yay
  }
}

new ClassTest({
  option: {},

  // val parameter properly infers the type of option
  test: _val => ({
    yo: { yo: {} },
  }),

  // Val's type is 'unknown' and not the return type of test :(
  check: val => { 
    val.yo;
  }
});

With a tiny change to setting the inferred property to an explicit type, it works great now:

type TestType = {};

interface ITest<TProperty, TReturn> {
  option: TProperty;
  test(val: TProperty): TReturn;
  check(val: TReturn): void;
}

class ClassTest<TProperty, TReturn> {
  constructor(_o: ITest<TProperty, TReturn>) {
    // yay
  }
}

new ClassTest({
  option: {},

  // We explicitly set the type this time
  test: (_val: TestType) => ({
    yo: { yo: {} },
  }),

  // Val's type is magically known :)
  check: val => { 
    val.yo;
  }
});

Expected behavior:

The TReturn should be inferred whether the TProperty is explicitly set in the parameter of the test method or not.

I would expect this because the system is able to infer TProperty just fine without me setting it in test.

Actual behavior:

TReturn is only inferred if TProperty for the parameter in the method is explicitly set even though TProperty can be inferred from the property just fine.

Playground Link:

Failing inference:
fails

Fixed inference:
works

@RyanCavanaugh RyanCavanaugh added the Design Limitation Constraints of the existing architecture prevent this from being fixed label Jun 26, 2019
@RyanCavanaugh
Copy link
Member

During inference (under its current algorithm), TypeScript has to resolve the entire shape of the object literal at once. At that point, there's a context-sensitive function for test, wherein the reasonable assumption is that the return type of test will rely on the parameter type for val (which in practice it always does). Therefore there's no inference candidate at all for TReturn (certainly check can't provide one) and the fallback zero-candidate unknown (previously {} is chosen instead).

The only algorithm that can correctly do this is unification (#30134) since there's no way to predict in advance how many passes* of inference need to be done before all types of parameters are resolved. The current algorithm is effectively limited to exactly three passes which are grouped by expression form.

See also #30134

*
image

@mAAdhaTTah
Copy link

I believe I've got a stripped-down example of this problem (extracted from an attempt to make this work in a library):

interface FnPair<W, X, Y, Z> {
  wy: (w: W) => X;
  yx: (x: X) => Y,
  zy: (y: Y) => Z
}
function compose<W, X, Y, Z>({wy, yx, zy}: FnPair<W, X, Y, Z>): (x: X) => Z {
  return x => zy(yx(x));
}
compose({
  wy: () => ({ world: 345 }),
  yx: w => ({ hello: w.world }),
  zy: (y) => (y.hello)
});

y is inferred as unknown, which looks very similar to what OP posted about. Would like it to be inferred as the return type of yx.

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
Projects
None yet
Development

No branches or pull requests

3 participants