Skip to content

Overloaded function with at least one generic overload can be assigned to any function with at least the same number of parameters #50050

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

Open
otonashixav opened this issue Jul 26, 2022 · 2 comments
Assignees
Labels
Needs Investigation This issue needs a team member to investigate its status.

Comments

@otonashixav
Copy link

otonashixav commented Jul 26, 2022

Bug Report

πŸ”Ž Search Terms

overload, generic, function

πŸ•— Version & Regression Information

  • This is the behavior in every version I tried, and I reviewed the FAQ for entries about overloads and generics.

⏯ Playground Link

Playground link with relevant code

πŸ’» Code

// only overloaded
function a(value: string): void;
function a(value: number): void;
function a(value: string | number) { value.toString() };

// only generic
function b<T extends number>(value: T): void { value.toString() };

// overloaded with generic
function c(value: string): void;
function c<T extends number>(value: T): void;
function c(value: string | number) { value.toString() };

// these are errors as expected
() => {
    let d: (value: unknown) => void = a;
    let e: (value: unknown) => void = b;
    c(null);
}

// this should be an error
let f: (value: unknown) => void = c;
f(null);

πŸ™ Actual behavior

In the example above I call f(null) and cause a runtime error, however typescript doesn't warn me about it.

πŸ™‚ Expected behavior

c should not be assignable to (value: unknown) => void.

@RyanCavanaugh RyanCavanaugh added the Needs Investigation This issue needs a team member to investigate its status. label Jul 28, 2022
@ahejlsberg
Copy link
Member

This is a known and long standing issue. In overloaded functions we erase type parameters (by substituting the any type) when relating signatures. From a comment in signaturesRelatedTo:

// For simple functions (functions with a single signature) we only erase type parameters for
// the comparable relation. Otherwise, if the source signature is generic, we instantiate it
// in the context of the target signature before checking the relationship. Ideally we'd do
// this regardless of the number of signatures, but the potential costs are prohibitive due
// to the quadratic nature of the logic below.

We could reconsider and attempt to fix this, but it will undoubtedly be a breaking change. For example, in #48092 we stop erasing type parameters for instantiations of the same generic type, but we never merged that PR due to the breaks it created.

This issue is basically a duplicate of #26631, and probably several others.

@niklasholm
Copy link

@ahejlsberg Interesting, I ran into a similar issue where the compiler would accept unsound generic overload signatures and came looking for answers, but found nothing in the documentation. If the compiler replaces generic types in overload signatures with any, the behavior I'm seeing makes sense. Should there not be some mention of this pretty serious limitation in the documentation?

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

No branches or pull requests

4 participants