How to infer event type using generics in polymorphic component

Viewed 69

I have a polymorphic component in which I try to infer event type by generic. Unfortunately, typescript is screaming about incompatible types.

import React, { forwardRef } from "react";

export type InferElement<T> = T extends keyof JSX.IntrinsicElements
  ? JSX.IntrinsicElements[T] extends React.DetailedHTMLProps<
      React.AnchorHTMLAttributes<any>,
      infer Elem
    >
    ? Elem
    : never
  : HTMLElement;

export type PolymorphicRef<
  C extends React.ElementType
> = React.ComponentPropsWithRef<C>["ref"];

type ComponentProp<C extends React.ElementType> = {
  component?: C;
};

type PropsToOmit<C extends React.ElementType, P> = keyof (ComponentProp<C> & P);

type PolymorphicComponentProp<
  C extends React.ElementType,
  Props = {}
> = React.PropsWithChildren<Props & ComponentProp<C>> &
  Omit<React.ComponentPropsWithoutRef<C>, PropsToOmit<C, Props>>;

export type PolymorphicComponentPropWithRef<
  C extends React.ElementType,
  Props = {}
> = PolymorphicComponentProp<C, Props> & { ref?: PolymorphicRef<C> };

interface AStaticProps<C extends React.ElementType> {
  onClick?: (event: React.MouseEvent<InferElement<C>, MouseEvent>) => void;
}

type AProps<C extends React.ElementType> = PolymorphicComponentPropWithRef<
  C,
  AStaticProps<C>
>;

type AComponent = <C extends React.ElementType = "div">(
  props: AProps<C>
) => React.ReactElement | null;

const A: AComponent = forwardRef(
  <C extends React.ElementType = "div">(
    { component, onClick, ...rest }: AProps<C>,
    ref?: PolymorphicRef<C>
  ) => {
    const Component = component || "div";

    return (
      <Component {...rest} onClick={onClick}>
        children
      </Component>
    );
  }
);

export default A;

Types of property 'onClick' are incompatible. Type '((event: MouseEvent<InferElement, MouseEvent>) => void) | undefined' is not assignable to type 'MouseEventHandler | undefined'.

Codesanbox

0 Answers
Related