[React Typescript] Strongly typed React component `as`

发布时间 2023-08-31 19:56:29作者: Zhentiw

The `as` Prop in React

Option 1:

import { Equal, Expect } from '../helpers/type-utils';

export const Wrapper = <TProps extends keyof JSX.IntrinsicElements>(
  props: {
    as: TProps;
  } & JSX.IntrinsicElements[TProps]
) => {
  const Comp = props.as as string;
  return <Comp {...(props as JSX.IntrinsicElements[TProps])}></Comp>;
};

const Example1 = () => {
  return (
    <>
      <Wrapper
        as="button"
        // @ts-expect-error doesNotExist is not a valid prop
        doesNotExist
      ></Wrapper>

      <Wrapper
        as="button"
        // e should be inferred correctly
        onClick={(e) => {
          type test = Expect<
            Equal<typeof e, React.MouseEvent<HTMLButtonElement>>
          >;
        }}
      ></Wrapper>
    </>
  );
};

/**
 * Should work specifying a 'div'
 */

const Example2 = () => {
  return (
    <>
      <Wrapper
        as="div"
        // @ts-expect-error doesNotExist is not a valid prop
        doesNotExist
      ></Wrapper>

      <Wrapper
        as="div"
        // e should be inferred correctly
        onClick={(e) => {
          type test = Expect<Equal<typeof e, React.MouseEvent<HTMLDivElement>>>;
        }}
      ></Wrapper>
    </>
  );
};

 

Option 2: A huge distrination union

export const Wrapper = <TAs extends keyof JSX.IntrinsicElements>(
  props: {
    as: TAs;
  } & ComponentProps<TAs>
) => {
  const Comp = props.as as string;

  return <Comp {...(props as any)}></Comp>;
};