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 inference fails to apply to functions as args #29775

Closed
ericanderson opened this issue Feb 6, 2019 · 1 comment
Closed

Type inference fails to apply to functions as args #29775

ericanderson opened this issue Feb 6, 2019 · 1 comment
Assignees
Labels
Fixed A PR has been merged for this issue Needs Investigation This issue needs a team member to investigate its status.

Comments

@ericanderson
Copy link
Contributor

ericanderson commented Feb 6, 2019

TypeScript Version: 3.2 and up (possibly older ones too)

Code

declare class Component<P> { 
  constructor(props: P);
}
    
interface ComponentClass<P = {}> {
  new (props: P): Component<P>;
}

type CreateElementChildren<P> =
  P extends { children?: infer C }
  ? C extends any[]
    ? C
    : C[]
  : unknown;

declare function createElement<P extends {}>(
  type: ComponentClass<P>,
  ...children: CreateElementChildren<P>
): any;

declare function createElement2<P extends {}>(
  type: ComponentClass<P>,
  child: CreateElementChildren<P>
): any;
        
// To be sure the optional isn't the problem:
class InferFunctionTypes extends Component<{children: (foo: number) => string}> {}
createElement(InferFunctionTypes, (foo) => "" + foo); // ERROR! Parameter 'foo' implicitly has an 'any' type.
// In the above, P is properly infered on the createElement, per hover tooltip:
// function createElement<{ children: (foo: number) => string; }>(type: ComponentClass<{ children: (foo: number) => string; }>, ...children: ((foo: number) => string)[]): any 

// If you don't expect P to be infered, it works properly:
createElement<{ children: (foo: number) => string }>(InferFunctionTypes, foo => "" + foo);

// Is unrelated to varargs
createElement2(InferFunctionTypes, [(foo) => "" + foo]); // ERROR! Parameter 'foo' implicitly has an 'any' type.

Expected behavior:

Typescript should be able to infer that foo is a number.

Actual behavior:

Parameter 'foo' implicitly has an 'any' type.

Playground Link:
http://www.typescriptlang.org/play/#src=declare%20class%20Component%3CP%3E%20%7B%20%0A%20%20constructor(props%3A%20P)%3B%0A%7D%0A%20%20%20%20%0Ainterface%20ComponentClass%3CP%20%3D%20%7B%7D%3E%20%7B%0A%20%20new%20(props%3A%20P)%3A%20Component%3CP%3E%3B%0A%7D%0A%0Atype%20CreateElementChildren%3CP%3E%20%3D%0A%20%20P%20extends%20%7B%20children%3F%3A%20infer%20C%20%7D%0A%20%20%3F%20C%20extends%20any%5B%5D%0A%20%20%20%20%3F%20C%0A%20%20%20%20%3A%20C%5B%5D%0A%20%20%3A%20unknown%3B%0A%0Adeclare%20function%20createElement%3CP%20extends%20%7B%7D%3E(%0A%20%20type%3A%20ComponentClass%3CP%3E%2C%0A%20%20...children%3A%20CreateElementChildren%3CP%3E%0A)%3A%20any%3B%0A%0Adeclare%20function%20createElement2%3CP%20extends%20%7B%7D%3E(%0A%20%20type%3A%20ComponentClass%3CP%3E%2C%0A%20%20child%3A%20CreateElementChildren%3CP%3E%0A)%3A%20any%3B%0A%20%20%20%20%20%20%20%20%0A%2F%2F%20To%20be%20sure%20the%20optional%20isn't%20the%20problem%3A%0Aclass%20InferFunctionTypes%20extends%20Component%3C%7Bchildren%3A%20(foo%3A%20number)%20%3D%3E%20string%7D%3E%20%7B%7D%0AcreateElement(InferFunctionTypes%2C%20(foo)%20%3D%3E%20%22%22%20%2B%20foo)%3B%20%2F%2F%20ERROR!%20Parameter%20'foo'%20implicitly%20has%20an%20'any'%20type.%0A%2F%2F%20In%20the%20above%2C%20P%20is%20properly%20infered%20on%20the%20createElement%2C%20per%20hover%20tooltip%3A%0A%2F%2F%20function%20createElement%3C%7B%20children%3A%20(foo%3A%20number)%20%3D%3E%20string%3B%20%7D%3E(type%3A%20ComponentClass%3C%7B%20children%3A%20(foo%3A%20number)%20%3D%3E%20string%3B%20%7D%3E%2C%20...children%3A%20((foo%3A%20number)%20%3D%3E%20string)%5B%5D)%3A%20any%20%0A%0A%2F%2F%20If%20you%20don't%20expect%20P%20to%20be%20infered%2C%20it%20works%20properly%3A%0AcreateElement%3C%7B%20children%3A%20(foo%3A%20number)%20%3D%3E%20string%20%7D%3E(InferFunctionTypes%2C%20foo%20%3D%3E%20%22%22%20%2B%20foo)%3B%0A%0A%2F%2F%20Is%20unrelated%20to%20varargs%0AcreateElement2(InferFunctionTypes%2C%20%5B(foo)%20%3D%3E%20%22%22%20%2B%20foo%5D)%3B%0A

Related Issues:

@ericanderson
Copy link
Contributor Author

Thank you @ahejlsberg and everyone!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Fixed A PR has been merged for this issue Needs Investigation This issue needs a team member to investigate its status.
Projects
None yet
Development

No branches or pull requests

3 participants