Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Save Mix-Liten/6d7238f2a0e888631179b9e2c06918e1 to your computer and use it in GitHub Desktop.
Save Mix-Liten/6d7238f2a0e888631179b9e2c06918e1 to your computer and use it in GitHub Desktop.
import React from "react";
type AsProp<C extends React.ElementType> = {
as?: C;
};
type PropsToOmit<C extends React.ElementType, P> = keyof (AsProp<C> & P);
/******************************************
** Not Support Refs version type utility **
******************************************/
type PolymorphicComponentProp<
C extends React.ElementType,
Props = {}
> = React.PropsWithChildren<Props & AsProp<C>> &
Omit<React.ComponentPropsWithoutRef<C>, PropsToOmit<C, Props>>;
// The type for the "ref" only
type PolymorphicRef<C extends React.ElementType> = React.ComponentPropsWithRef<
C
>["ref"];
/**************************************
** Support Refs version type utility **
**************************************/
type PolymorphicComponentPropWithRef<
C extends React.ElementType,
Props = {}
> = PolymorphicComponentProp<C, Props> & { ref?: PolymorphicRef<C> };
/***************************
** Example text component **
***************************/
type Rainbow =
| "red"
| "orange"
| "yellow"
| "green"
| "blue"
| "indigo"
| "violet";
type TextProps<C extends React.ElementType> = PolymorphicComponentPropWithRef<
C,
{ color?: Rainbow | "black" }
>;
/**
* This is the type used in the type annotation for the component
*/
type TextComponent = <C extends React.ElementType = "span">(
props: TextProps<C>
) => React.ReactElement | null;
const Text: TextComponent = React.forwardRef(
<C extends React.ElementType = "span">(
{ as, color, children }: TextProps<C>,
ref?: PolymorphicRef<C>
) => {
const Component = as || "span";
const style = color ? { style: { color } } : {};
return (
<Component {...style} ref={ref}>
{children}
</Component>
);
}
);
export default Text;
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment