How do I leverage type inference for nested function parameters?

I'm having trouble with type inference on this function. It seems to work intermittently. Sometimes it infers the type {} and other times it will infer the correct type. Here is an example:

function foo<T>(a: (b: () => T) => T) {
  const b = () => value;
  const value = a(b);
  return value;
}

const v = foo(b => 'a'); // 'v: {}' but should be 'v: string'

I could declare the type for b when I call foo() but foo is sometimes called from JS and I wanted to leverage IntelliSense while working in JS. Is there another way I can do this?

Additional info:

  • TypeScript v3.4.3
  • Using VSCode to inspect types

Screenshot of it working intermittently: https://i.imgur.com/dRC8ab7.png

Posted Apr 17, 2019, 5:19 PM UTC · edited

35
amZNeZk1•

Try this one:

function foo<T, B extends () => T>(a: (b: B) => T) {
  const b = (() => value) as B;
  const value = a(b);
  return value;
}

const v = foo(b => 'a');
3
ProfessorTagOP•

Thank you!

2
Uiropa•

I’ve been staring at this for a long time, but what is it supposed to do? The way the value const is defined to have the value of a function call that returns value itself looks like a sadistic interview question, or just something out of Lovecraft.

3
ProfessorTagOP•

Ha ha! I'm sorry. I reduced the code for this example and it doesn't really accomplish anything. It just shows the strange behavior.

1
dangertrager•

Your reuse of variable names confuses any discussion of the code. Hopefully renaming them makes it clearer.

function foo<T>(giveMeT: (callback: () => T) => T) {`
  const throwAnException = () => value; // will throw because value is not declared
  const returnValue = giveMeT(throwAnException);
  return returnValue;
}

const v = foo(unusedCallback => 'a'); // since unusedCallback is unused, throwAnException is not called

throwAnException does not return a T. Ideally that would cause a compile error to help you identify the problem, but apparently it doesn't.

2