nasheomirro / react-polymorphed

A set of types to help easily create fast polymorphic components.
MIT License
25 stars 3 forks source link

Once built, polymorphed types become generic "string" types #10

Open mririgoyen opened 6 months ago

mririgoyen commented 6 months ago

I'm using your package to create polymorphic components that forward refs. Using the following pattern, everything works as intended within the local component library.

import { forwardRef } from 'react';
import { type PolyRefFunction } from 'react-polymorphed';

import { type TypographyProps } from './Typography.props';

const forwardPolymorphicRef = forwardRef as PolyRefFunction;

export const Typography = forwardPolymorphicRef<'span', TypographyProps>(
  (
    {
      align = 'inherit', // This is an enum of 'center | left | right | inherit'
      as,
    }
    ref,
  ) => { ... };

As I said, when used locally, such as in my Storybook examples, TypeScript sees and enforces the types.

Screenshot 2024-04-09 at 10 14 12 AM


However, after building the package with Rollup and importing it into another repository, all the types get genericized. This only happens on components wrapped with this polymorph utility.

Screenshot 2024-04-09 at 10 15 58 AM

Following the types, I see a logical chain to my eventual prop types that are correct.

declare const Typography: react_polymorphed.PolyForwardComponent<"span", TypographyProps, react.ElementType<any, keyof react.JSX.IntrinsicElements>>;

...

interface TypographyProps extends TypographyVariantProps {
    /**
     * Set the text-align on the component.
     * @default inherit
     */
    align?: NonNullable<TypographyVariantProps['align']>;
}

...

type TypographyVariantProps = VariantProps<typeof TypographyVariants>;

...

declare const TypographyVariants: (props?: ({
    align?: "center" | "inherit" | "left" | "right" | null | undefined;
} & class_variance_authority_types.ClassProp) | undefined) => string;

I've traced other components that are not polymorphic and they all follow the same exact pattern, except the first step is a direct call to the React forwardRefExcoticComponent. These all type correctly.

declare const Tooltip: react.ForwardRefExoticComponent<TooltipProps & react.RefAttributes<HTMLDivElement>>;

My question is, am I doing something incorrect at some step that could potentially cause this? Losing type safety on polymorphic components isn't good, so I need to figure out how to resolve this.

nasheomirro commented 6 months ago

I haven't really used this package to make another package, but I don't see how that should break things. I guess you could try to check what TypographyProps is first, I'm pretty sure you could also install react-polymorphed in the user-side to check whether we get the same thing:

import { TypographyProps } from "your-package";
import { PolyForwardComponent } from "react-polymorphed";

// test A
declare const props: TypographyProps;
// test if typography props still has the correct 'align' type
props.align = '';

// test B
declare const Test: PolyForwardComponent<'span', TypographyProps>;
// check if it works when used directly
<Test align='left' /> 

Simplest case is both test A and test B failing, if so then most likely rollup is messing up your own types somehow, if both test A and test B succeed then something might have went wrong with rollup figuring out polymorphic components?? If test A succeeds and test B fails then there's something very wrong with this package.

mririgoyen commented 6 months ago

I haven't really used this package to make another package, but I don't see how that should break things. I guess you could try to check what TypographyProps is first, I'm pretty sure you could also install react-polymorphed in the user-side to check whether we get the same thing:

import { TypographyProps } from "your-package";
import { PolyForwardComponent } from "react-polymorphed";

// test A
declare const props: TypographyProps;
// test if typography props still has the correct 'align' type
props.align = '';

// test B
declare const Test: PolyForwardComponent<'span', TypographyProps>;
// check if it works when used directly
<Test align='left' /> 

Simplest case is both test A and test B failing, if so then most likely rollup is messing up your own types somehow, if both test A and test B succeed then something might have went wrong with rollup figuring out polymorphic components?? If test A succeeds and test B fails then there's something very wrong with this package.

Thanks for the response. I'm going to set up and test each of these cases. I will report back with my findings.

mririgoyen commented 6 months ago

Both tests pass. I suppose I will start debugging Rollup now.

Screenshot 2024-04-09 at 2 01 34 PM