Home > Net >  Type is not assignable to type LibraryManagedAttributes
Type is not assignable to type LibraryManagedAttributes

Time:03-18

I am trying to create array field component that will accept any React Functional component that has BaseProps. However I get an error when rendering Component in ArrayField.

enter image description here

Please see code below. Any ideas what's wrong here?

type BaseProps<T> = {
  name: string;
  convertValue?: (value: T) => T;
};

type CompanyType = {
  address: string;
  employees: number;
};

type CompanyProps = BaseProps<CompanyType> & {
  required?: boolean;
};

const Company = (props: CompanyProps) => {
  return <div>{/** */}</div>;
};

type ArrayFieldProps<T, V extends React.FC<BaseProps<T>>> = {
  Component: V;
  componentProps: React.ComponentProps<V>;
  values: T[];
};

const ArrayField = <T, V extends React.FC<BaseProps<T>>>({
  Component,
  values,
  componentProps
}: ArrayFieldProps<T, V>) => {
  return (
    <React.Fragment>
      {values.map((_, index) => (
        <Component key={index} {...componentProps} />
      ))}
    </React.Fragment>
  );
};

export const App = () => {
  const companies: CompanyType[] = [];

  return (
    <ArrayField
      values={companies}
      Component={Company}
      componentProps={{
        name: 'company',
        convertValue: (value) => ({
          ...value,
          address: value.address.toUpperCase()
        }),
        required: true
      }}
    />
  );
};

CodePudding user response:

I would do it slightly differently. Component types are quite complex so IMO it's easier to reason about simpler types, and it this scenario it solves your problem. Instead of using the Component as a "base" for your interface, use props. Like this:

type BaseProps<T> = {
  name: string;
  convertValue?: (value: T) => T;
};

type ArrayFieldProps<T, P extends BaseProps<T>> = {
  Component: React.ComponentType<P>;
  componentProps: P;
  values: T[];
};

const ArrayField = <T, P extends BaseProps<T>>({
  Component,
  values,
  componentProps
}: ArrayFieldProps<T, P>) => {
  return (
    <>
      {values.map((_, index) => (
        <Component key={index} {...componentProps} />
      ))}
    </>
  );
};

So as you can see the main difference is that the second generic type has to extend BaseProps<T> instead of a component type with specific props (this is most likely where TypeScript gives up and it results in problems with key prop) and ultimately you want your Component to be any valid React component (whether it's class or a function one). Of course if you really insist on enforcing function components you can change React.ComponentType to React.FC and it would still work.

CodePudding user response:

You have to take into consideration the

key={index}

portion because there is a mismatch from the expected type and what is passed. This portion is not included in any of the types and I guess typescript just interprets it as value to be passed (not actual key).

You may try to move it on outer div just to see if the situation improves.

  • Related