newbie
newbie

Reputation: 600

React Proptypes gives error while generating Proptypes for a component

I am getting an error with PropTypes. The Props are:

type FieldTypes = 'dropdown' | 'checkbox';

type PluginDropdownData = {
  label: string;
  value: string;
};

type PluginManifestObject = {
  label: string;
  type: FieldTypes;
  data: Array<PluginDropdownData> | Array<string>;
  mandatory: boolean;
};

{
  manifestObject: PluginManifestObject
  objectKey: string;
  handleValueChange: (label: string, value: string | boolean) => void;
  initialValue: string | boolean;
}

This is my solution:

 ComponentA.propTypes = {
  manifestObject: PropTypes.shape({
    label: PropTypes.string.isRequired,
    type: PropTypes.oneOf(['dropdown', 'checkbox']).isRequired,
    data: PropTypes.oneOfType([
      PropTypes.arrayOf(PropTypes.shape({
        label: PropTypes.string.isRequired,
        value: PropTypes.string.isRequired,
      })),
      PropTypes.arrayOf(PropTypes.string),
    ]).isRequired,
    mandatory: PropTypes.bool.isRequired,
  }).isRequired,,
  objectKey: PropTypes.string.isRequired,
  handleValueChange: PropTypes.func.isRequired,
  initialValue: PropTypes.oneOfType([
    PropTypes.string,
    PropTypes.bool,
  ]).isRequired,
};

But I am getting 2 errors:

Type 'Validator<InferProps<{ label: Validator<string>; type: Validator<string>; data: Validator<(InferProps<{ label: Validator<string>; value: Validator<string>; }> | null | undefined)[] | (string | ... 1 more ... | undefined)[]>; mandatory: Validator<...>; }>>' is not assignable to type 'Validator<PluginManifestObject>'.
  Type 'InferProps<{ label: Validator<string>; type: Validator<string>; data: Validator<(InferProps<{ label: Validator<string>; value: Validator<string>; }> | null | undefined)[] | (string | ... 1 more ... | undefined)[]>; mandatory: Validator<...>; }>' is not assignable to type 'PluginManifestObject'.
    Types of property 'type' are incompatible.
      Type 'string' is not assignable to type 'FieldTypes'.ts(2322)
(property) manifestObject?: React.Validator<PluginManifestObject> | undefined

The above error is fixed by aleksxor answer but there is still one error, i.e.

Type 'Validator<InferProps<{ label: Validator<string>; type: Validator<"input" | "dropdown" | "checkbox" | "date" | "radio" | "range">; data: Validator<(InferProps<{ label: Validator<string>; value: Validator<...>; }> | null | undefined)[] | (string | ... 1 more ... | undefined)[]>; mandatory: Validator<...>; }>>' is not assignable to type 'Validator<PluginManifestObject>'.
  Type 'InferProps<{ label: Validator<string>; type: Validator<"input" | "dropdown" | "checkbox" | "date" | "radio" | "range">; data: Validator<(InferProps<{ label: Validator<string>; value: Validator<...>; }> | null | undefined)[] | (string | ... 1 more ... | undefined)[]>; mandatory: Validator<...>; }>' is not assignable to type 'PluginManifestObject'.
    Types of property 'data' are incompatible.
      Type '(InferProps<{ label: Validator<string>; value: Validator<string>; }> | null | undefined)[] | (string | null | undefined)[]' is not assignable to type 'string[] | PluginDropdownData[]'.
        Type '(InferProps<{ label: Validator<string>; value: Validator<string>; }> | null | undefined)[]' is not assignable to type 'string[] | PluginDropdownData[]'.
          Type '(InferProps<{ label: Validator<string>; value: Validator<string>; }> | null | undefined)[]' is not assignable to type 'string[]'.
            Type 'InferProps<{ label: Validator<string>; value: Validator<string>; }> | null | undefined' is not assignable to type 'string'.
              Type 'undefined' is not assignable to type 'string'.ts(2322)
(property) manifestObject?: React.Validator<PluginManifestObject> | undefined

I am not sure what I am missing here. Can someone please help me with this?

Thanks

Upvotes: 1

Views: 915

Answers (1)

aleksxor
aleksxor

Reputation: 8380

The problem is you're passing non-readonly array to the oneOf validator. And the values of non-readonly array are inferred as string type. The solution is pretty simple. Just pass it readonly tuple:

   ...
   type: PropTypes.oneOf(['dropdown', 'checkbox'] as const).isRequired,
   ...

Updated answer to address the second error.

To match the type: data: Array<PluginDropdownData> | Array<string> you have to define your propTypes as:

   ...
   data: PropTypes.oneOfType([
       PropTypes.arrayOf(PropTypes.shape({
           label: PropTypes.string.isRequired,
           value: PropTypes.string.isRequired,
       }).isRequired),
       PropTypes.arrayOf(PropTypes.string.isRequired),
   ]).isRequired,

Notice that if you want the array to pass the validation you have to declare it's elements as isRequired. If you're not planning to make them isRequired you have to add | null | undefined to array's item type. For example those two definitions pass without error:

type PluginManifestObject = {
   ...
   data: Array<PluginDropdownData | undefined | null> | Array<string | undefined | null>
   ...
}

   ...
   data: PropTypes.oneOfType([
      PropTypes.arrayOf(PropTypes.shape({
          label: PropTypes.string.isRequired,
          value: PropTypes.string.isRequired,
      })),
      PropTypes.arrayOf(PropTypes.string),
  ]).isRequired,
  ...

Upvotes: 1

Related Questions