Skip to content

[Bug] JSX property generic inference dumber than function object generic infernce #53789

@jeengbe

Description

@jeengbe

Bug Report

I have difficulty naming the issue, please suggest/make changes to the title/search terms.

🔎 Search Terms

Function, JSX, inferring, generic, difference, inference priority

🕗 Version & Regression Information

  • This is the behavior in every version I tried, and I reviewed the FAQ for entries about n/a

⏯ Playground Link

Playground link with relevant code

💻 Code

import React from "react";

type TranslationEntry = {
    args: [] | [unknown];
}
type Translations = {
    a: { args: [string] },
    b: { args: [] }
}

// Relation:
// Translations satisfies Record<string, TranslationEntry>

// If the selected translation entry requires arguments, intersect with object that requires 'args'
type TProps<Entry extends TranslationEntry> = {
    getTranslationEntry: (allTranslations: Translations) => Entry,
} & (Entry["args"] extends [unknown] ? {
    args: Entry["args"][0]
} : {});

declare function T<Entry extends TranslationEntry>(
    props: TProps<Entry>
): JSX.Element;

// Calling the function directly works
T({
    getTranslationEntry: (allTranslations) => allTranslations.a,
    args: "a"
});

// But the JSX version, however, doesn't
<T
    getTranslationEntry={(allTranslations) => allTranslations.a}
    args="a"
//  ^^^^ Property 'args' does not exist on type 'IntrinsicAttributes & { getTranslationEntry: (allTranslations: Translations) => TranslationEntry; }'
/>

To add some context to above code

<T /> is a component that uses the form <T getTranslationEntry={ t => t.xyz } /> to specify which translation (entry) to display. Depending on what's selected, additional arguments are required.
In order to be able to omit the args prop when not required, the intersection with

(Entry["args"] extends [unknown] ? {
    args: Entry["args"][0]
} : {})

does this.

🙂 Expected behavior

As it does for the function call, for the JSX element should infer it's generic parameter E to { args: [string] }. Because of this, Entry["args"] extends [unknown] ? ... : { } then correctly resolves to { args: string }

🙁 Actual behavior

Entry["args"] extends [unknown] ? ... : { } resolves to { } instead, but strangely only for the JSX variant.

💡 Other

What is most confusing is the following seeming contradiction:

  <T
// ^Property 'args' is missing in type '{ getTranslationEntry: (allTranslations: Translations) => { args: [string]; }; }' but required in type '{ args: string; }'.
    getTranslationEntry={(allTranslations) => allTranslations.a}
/>;


<T
    getTranslationEntry={(allTranslations) => allTranslations.a}
    args="a"
//  ^^^^ Property 'args' does not exist on type 'IntrinsicAttributes & { getTranslationEntry: (allTranslations: Translations) => TranslationEntry; }'.
/>;

Metadata

Metadata

Assignees

No one assigned

    Labels

    BugA bug in TypeScriptDomain: JSX/TSXRelates to the JSX parser and emitterHelp WantedYou can do this

    Type

    No type

    Projects

    No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions