Skip to content

Instantly share code, notes, and snippets.

@ylyra
Created October 31, 2023 21:29
Show Gist options
  • Select an option

  • Save ylyra/18860b13228231f6b0fd3e36c413feb0 to your computer and use it in GitHub Desktop.

Select an option

Save ylyra/18860b13228231f6b0fd3e36c413feb0 to your computer and use it in GitHub Desktop.
Polymorphic forward-ref
import React from "react";
type As<P = any> = React.ElementType<P>;
type PropsOf<C extends As> = React.ComponentProps<C>;
type RightJoin<C extends {}, P extends {}> = Omit<C, keyof P> & P;
type Props<C> = C extends ForwardRefComponent<any, infer P> ? P : {};
type IntrinsicElement<C> = C extends ForwardRefComponent<infer I, any>
? I
: never;
type ForwardRefExoticComponent<C, OwnProps> = React.ForwardRefExoticComponent<
RightJoin<
C extends React.ElementType ? React.ComponentPropsWithRef<C> : never,
OwnProps & { as?: C }
>
>;
interface ForwardRefComponent<IntrinsicElementString, OwnProps = {}>
extends ForwardRefExoticComponent<IntrinsicElementString, OwnProps> {
<As = IntrinsicElementString>(
props: As extends ""
? { as: keyof JSX.IntrinsicElements }
: As extends React.ComponentType<infer P>
? RightJoin<P, OwnProps & { as: As }>
: As extends keyof JSX.IntrinsicElements
? RightJoin<JSX.IntrinsicElements[As], OwnProps & { as: As }>
: never
): React.ReactElement | null;
}
export const forwardRef = function <P extends object, C extends As>(
component: React.ForwardRefRenderFunction<
any,
RightJoin<PropsOf<C>, P> & {
as?: As;
}
>
) {
return React.forwardRef(component) as unknown as ForwardRefComponent<C, P>;
};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment