Skip to content

Instantly share code, notes, and snippets.

@xeladotbe
Forked from kripod/Box.tsx
Created November 27, 2022 19:48
Show Gist options
  • Save xeladotbe/7b3cf97008f7d4481e2361ee3e028af7 to your computer and use it in GitHub Desktop.
Save xeladotbe/7b3cf97008f7d4481e2361ee3e028af7 to your computer and use it in GitHub Desktop.
Polymorphic `as` prop for React components with TypeScript
import React from 'react';
// Source: https://github.com/emotion-js/emotion/blob/master/packages/styled-base/types/helper.d.ts
type PropsOf<
// eslint-disable-next-line @typescript-eslint/no-explicit-any
E extends keyof JSX.IntrinsicElements | React.JSXElementConstructor<any>
> = JSX.LibraryManagedAttributes<E, React.ComponentPropsWithRef<E>>;
export interface BoxOwnProps<E extends React.ElementType = React.ElementType> {
as?: E;
}
export type BoxProps<E extends React.ElementType> = BoxOwnProps<E> &
Omit<PropsOf<E>, keyof BoxOwnProps>;
export type PolymorphicComponentProps<E extends React.ElementType, P> = P &
BoxProps<E>;
const defaultElement = 'div';
export const Box = React.forwardRef(
({ as, ...restProps }: BoxOwnProps, ref: React.Ref<Element>) => {
const Element = as || defaultElement;
return <Element ref={ref} {...restProps} />;
},
) as <E extends React.ElementType = typeof defaultElement>(
props: BoxProps<E>,
) => JSX.Element;
/* Usage example: */
interface CustomComponentOwnProps {
customProp?: number;
onClick: boolean;
}
type CustomComponentProps<
E extends React.ElementType
> = PolymorphicComponentProps<E, CustomComponentOwnProps>;
function CustomComponent<E extends React.ElementType>(
props: CustomComponentProps<E>,
): JSX.Element {
return <Box {...props} />;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment