如何在多态组件中使用泛型推断事件类型

Pio*_*otr 5 generics polymorphism typescript reactjs typescript-generics

我有一个多态组件,我尝试通过泛型推断事件类型。不幸的是,打字稿正在尖叫不兼容的类型。

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;
Run Code Online (Sandbox Code Playgroud)

属性“onClick”的类型不兼容。类型 '((事件:MouseEvent<InferElement, MouseEvent>) => void) | 未定义' 不可分配给类型'MouseEventHandler | 不明确的'。

代码沙盒

Rob*_*ell 0

Element我可以通过使用orHTMLElement代替InferElement<C>in来消除错误AStaticProps,但我怀疑不使用你的InferElementwill 意味着你会失去在打字时所做的很多艰苦工作:

interface AStaticProps<C extends React.ElementType> {
  onClick?: (event: React.MouseEvent<HTMLElement, MouseEvent>) => void;
}
Run Code Online (Sandbox Code Playgroud)