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

Higher order type inference doesn't work with overloads #33594

Open
falsandtru opened this issue Sep 25, 2019 · 5 comments
Open

Higher order type inference doesn't work with overloads #33594

falsandtru opened this issue Sep 25, 2019 · 5 comments
Assignees
Labels
Suggestion An idea for TypeScript

Comments

@falsandtru
Copy link
Contributor

@ahejlsberg

TypeScript Version: typescript@3.7.0-dev.20190925

Search Terms:

Code

interface Curried2<a, b, z> {
  (a: a, b: b): z;
  (a: a): (b: b) => z;
}
interface Curry {
  <a, b, z>(f: (a: a, b: b) => z): Curried2<a, b, z>;
}

declare const curry: Curry;

curry(<T extends 0, U extends 1>(n: T, m: U) => n + m)(1)(0);
curry(<T extends 0, U extends 1>(n: T, m: U) => n + m)(1, 0);

Also the following doesn't work:

interface Curried2<a, b, z> {
  (a: a): (b: b) => z;
  (a: a, b: b): z;
}

When removing overloads as follows:

interface Curried2<a, b, z> {
  (a: a, b: b): z;
}

or

interface Curried2<a, b, z> {
  (a: a): (b: b) => z;
}

These work correctly.

Expected behavior:

Infer type parameters correctly and all parameter values are rejected correctly.

Actual behavior:

no error.

Playground Link:

Related Issues:

@falsandtru falsandtru changed the title Higher order function doesn't work with overloads Higher order type inference doesn't work with overloads Sep 25, 2019
@RyanCavanaugh RyanCavanaugh added Design Limitation Constraints of the existing architecture prevent this from being fixed Needs Investigation This issue needs a team member to investigate its status. and removed Design Limitation Constraints of the existing architecture prevent this from being fixed labels Sep 25, 2019
@RyanCavanaugh RyanCavanaugh added this to the TypeScript 3.8.0 milestone Sep 25, 2019
@RyanCavanaugh
Copy link
Member

@ahejlsberg can you comment? I'm not 100% sure on this one

@ahejlsberg
Copy link
Member

This is indeed a known design limitation. From #30215:

When an argument expression in a function call is of a generic function type, the type parameters of that function type are propagated onto the result type of the call if:

  • the called function is a generic function that returns a function type with a single call signature,
    ...

We can mark this as a suggestion to support more than one signature in the result function type. It's possible to do, but not trivial.

@ahejlsberg ahejlsberg added Suggestion An idea for TypeScript and removed Needs Investigation This issue needs a team member to investigate its status. labels Oct 3, 2019
@ahejlsberg ahejlsberg removed this from the TypeScript 3.8.0 milestone Nov 20, 2019
@treybrisbane
Copy link

Just got hit by this while trying to describe the notion of a generic callable class:

class Foo<T> {
  constructor(readonly value: T) {}
}

function callable<P extends readonly any[], R>(Constructor: new (...params: P) => R): typeof Constructor & ((...params: P) => R) {
  return function (...params) {
    return new Constructor(...params);
  } as typeof Constructor & ((...params: P) => R);
}

const CallableFoo = callable(Foo);
// => (new (value: any) => Foo<any>) & ((value: any) => Foo<any>)
// Should be: (new <T>(value: T) => Foo<T>) & (<T>(value: T) => Foo<T>)

const foo1 = CallableFoo(42);
// => Foo<any>
// Should be: Foo<number>

const foo2 = new CallableFoo(42);
// => Foo<any>
// Should be: Foo<number>

@ahejlsberg
Copy link
Member

@treybrisbane Why not just the following?

function callable<A extends readonly any[], R>(ctor: new (...args: A) => R): (...args: A) => R {
  return (...args) => new ctor(...args);
}

@treybrisbane
Copy link

@ahejlsberg In my case I'm trying to enable types to be both instantiable via new and callable. 🙂

I believe I can work around it. I just figured I'd leave a comment anyway, as I found it confusing that the higher-order inference didn't kick in given that my two overloads are identical in terms of parameters and result.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Suggestion An idea for TypeScript
Projects
None yet
Development

No branches or pull requests

4 participants