Skip to content

Inconsistency in generic parameter inference #38264

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
ilogico opened this issue Apr 30, 2020 · 2 comments
Open

Inconsistency in generic parameter inference #38264

ilogico opened this issue Apr 30, 2020 · 2 comments
Labels
Needs Investigation This issue needs a team member to investigate its status.
Milestone

Comments

@ilogico
Copy link

ilogico commented Apr 30, 2020

TypeScript Version: 3.8.3, nightly, etc.

Search Terms: infer function return

Code

declare function h<T extends keyof HTMLElementTagNameMap>(
    tag: T,
    ...init: ((e: HTMLElementTagNameMap[T]) => void)[],
): HTMLElementTagNameMap[T];

declare function events<T extends HTMLElement>(
    handlers: Partial<{ [K in keyof HTMLElementEventMap]: (this: T, e: HTMLElementEventMap[K]) => void }>
): (e: T) => void;

declare function props<T extends HTMLElement>(
    props: Partial<T>
): (e: T) => void;

h(
    'input',
    events({
        input() {
            this.value;
        },
    }),
    props({
        value: '42'
    })
)

Expected behavior:
no errors
Actual behavior:

    Argument of type '{ value: string; }' is not assignable to parameter of type 'Partial<HTMLElement>'. Object literal may only specify known properties, and 'value' does not exist in type 'Partial<HTMLElement>'.

Playground Link: playground

Related Issues: I'm pretty sure I didn't choose a decent title for the issue, so my ability to search for this is limited as well.

I can understand this could be viewed as feature request/improvement, but there are a couple of reasons that make the behaviour feel buggy:

  1. The inference works correctly for the events call, which is resolved as events<HTMLInputElement>.
  2. The intellisense works on the props argument, which means at some point, the compiler understands I'm writing a Partial<HTMLInputElement>. But for some reason, it resolves the call to props<HTMLElement>, so the code fails to typecheck. I can work around it by adding the type parameter, but it degrades de developing experience.
@ilogico
Copy link
Author

ilogico commented May 1, 2020

I have found a workaround, which is to declare props as:

declare function props<E extends Element, P extends Partial<E>>(props: P): (e: E) => void;

@RyanCavanaugh RyanCavanaugh added the Needs Investigation This issue needs a team member to investigate its status. label May 8, 2020
@RyanCavanaugh RyanCavanaugh added this to the Backlog milestone May 8, 2020
@ilogico
Copy link
Author

ilogico commented Mar 25, 2021

Testing this again, I noticed that, if props returns {}, the call is inferred as props<HTMLInputElement>({}), but adding the value (which shows up in autocomplete) transforms the call into props<HTMLElement>({ value: '42' }).

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

2 participants