Skip to content

Allow overloading of JSX element constructors #29025

Closed
@ferdaber

Description

@ferdaber

Search Terms

jsx overload conditional component react

Suggestion

Allow for some kind of overload mechanism for JSX element construction, that is: determine contextual types for the allowable attributes for a JSX expression based on attributes already passed in.

Use Cases

There are times when we want to conditionally render based on the type of a certain property in a props object, or the existence/non-existence of a certain property in a props object. A very common use case is rendering clickable elements as anchor tags if a href attribute is present:

type AnchorProps = JSX.IntrinsicElements['a']
type ButtonProps = JSX.IntrinsicElements['button']
declare function Buttonish(props: ButtonProps): JSX.Element
declare function Buttonish(props: AnchorProps): JSX.Element
declare function Buttonish(props: AnchorProps | ButtonProps): JSX.Element

const myAnchor = <Buttonish href="typescriptlang.org" onClick={event => {}} /> 
// `event` is inferred to be React.MouseEvent<HTMLAnchorElement> because `href` is already there

The above is one suggestion though I don't know we could resolve that with class-based components.

I know right now that this is partially solved with generic components + conditional types, but it's kind of odd DX:

type EitherProps<T> = T extends string ? { href?: T } & AnchorProps : { href?: undefined } & ButtonProps
declare function Buttonish<T>(props: EitherProps<T>): JSX.Element

const myAnchor = <Buttonish href="typescriptlang.org">
// generic type inferred, but looks weird since T = string which doesn't tell you much

Examples

Unsure what the best approach would be. I think one good DX I was hoping for was for the autocomplete list to be narrowed as attributes are added to a JSX expression, when the compiler gets more contextual information to infer, so that after href is added in the above example, the event handlers are narrowed to just be handlers related to anchor elements, for example.

Checklist

My suggestion meets these guidelines:

  • This wouldn't be a breaking change in existing TypeScript/JavaScript code
  • This wouldn't change the runtime behavior of existing JavaScript code
  • This could be implemented without emitting different JS based on the types of the expressions
  • This isn't a runtime feature (e.g. library functionality, non-ECMAScript syntax with JavaScript output, etc.)
  • This feature would agree with the rest of TypeScript's Design Goals.

Metadata

Metadata

Assignees

No one assigned

    Labels

    Needs More InfoThe issue still hasn't been fully clarified

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions