Skip to content

Inconsistency in generic parameter inference #38264

Open

Description

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.

Activity

  1. ilogico commented on May 1, 2020

    @ilogico
    Author

    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;
  2. ilogico commented on Mar 25, 2021

    @ilogico
    Author

    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

Metadata

Metadata

Assignees

No one assigned

    Labels

    Needs InvestigationThis issue needs a team member to investigate its status.

    Type

    No type

    Projects

    No projects

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions