Skip to content

Passing a generic component to as fails #15

Open

Description

@amannn

I've got a polymorphic button component that looks like this:

import type {PolymorphicPropsWithoutRef} from 'react-polymorphic-types';

const defaultElement = 'button';

type ButtonOwnProps = {
  color?: string;
};

type ButtonProps<T extends React.ElementType = typeof defaultElement> =
  PolymorphicPropsWithoutRef<ButtonOwnProps, T>;

function Button<T extends React.ElementType = typeof defaultElement>({
  as,
  color,
  ...rest
}: ButtonProps<T>) {
  const Element: React.ElementType = as || defaultElement;
  return <Element style={{color}} {...rest} />;
}

Simple cases work:

// ✅ Works
<Button as="a" href="/test">
  Two
</Button>;

… but when I pass a component to the as prop that is itself generic, I get an error.

function Test<Name extends 'one' | 'two'>({test}: {test: Name}) {
  return <>{test}</>;
}

// ❌ Fails
<Button as={Test} color="rebeccapurple" test="two">
  One
</Button>;
Type '{ children: string; as: <Name extends "one" | "two">({ test }: { test: Name; }) => Element; color: string; test: "two"; }' is not assignable to type 'IntrinsicAttributes & Omit<{ test: "one" | "two"; }, "as" | "color"> & ButtonOwnProps & { as?: (<Name extends "one" | "two">({ test }: { test: Name; }) => Element) | undefined; }'.
  Property 'children' does not exist on type 'IntrinsicAttributes & Omit<{ test: "one" | "two"; }, "as" | "color"> & ButtonOwnProps & { as?: (<Name extends "one" | "two">({ test }: { test: Name; }) => Element) | undefined; }'.ts(2322)

Can you provide some help for this use case @kripod? Thank you very much!

Activity

  1. amannn commented on Aug 28, 2023

    @amannn
    Author

    I believe it's this todo in the code base:

    // - PolymorphicFunctionComponent

  2. kripod commented on Mar 22, 2024

    @kripod
    Owner

    A component passed to as shouldn’t have any required props. Otherwise, specifying a generic component should be possible using a different approach for polymorphism as shown here.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions