0
votes

I'm writing a quick wrapper interface. I'm looking for some mystery types:

Let Foo be some React component that accepts props of type FooProps.

Let X be the interface that represents both any generic React component or any HTML element. Where Foo extends X but also div extends X. X is anything that can be turned into a JSX.Element by <X></X>

Let Y<T extends X> be the props of our T, which is again any element such as Foo or div. Where Y<Foo> = FooProps, and Y<div> = { className: string, ... }

We could write:

interface WrapperProps<T extends X>{
    children?: React.ReactNode;
    attributes?: Y<T>;
}

Then we could write:

const props: WrapperProps<T> = ...;
const el: JSX.Element = (
    <T {...attributes}>
        { children }
    </T>
);

What are these mystery types X and Y?

1

1 Answers

1
votes

I believe what you're looking for is:

type WrapperProps<T extends keyof JSX.IntrinsicElements | React.JSXElementConstructor<any>> = {
    children?: React.ReactNode;
    attributes: Omit<React.ComponentProps<T>, 'children'>;
}

playground link

Notice the required attributes property. While you can make any of the properties optional you cannot omit them at all.

React types used here:

JSX.IntrinsicElements (too big to include here).

JSXElementConstructor:

type JSXElementConstructor<P> =
    | ((props: P) => ReactElement<any, any> | null)
    | (new (props: P) => Component<P, any>);

ReactComponentProps:

type ComponentProps<T extends keyof JSX.IntrinsicElements | JSXElementConstructor<any>> =
    T extends JSXElementConstructor<infer P>
        ? P
        : T extends keyof JSX.IntrinsicElements
            ? JSX.IntrinsicElements[T]
            : {};