Home > Mobile >  react select - how to define component props type
react select - how to define component props type

Time:09-19

I use react-select in my project.
enter image description here

App.tsx

import "./styles.css";
import React, { useState } from "react";
import Select, { components, OptionProps } from "react-select";

const options = [
  {
    label: "label 1",
    value: "value 1",
    dialCode: "dialCode 1"
  },
  {
    label: "label 2",
    value: "value 2",
    dialCode: "dialCode 2"
  }
];

const { Option } = components;

const IconOption = (props: any) => {
  const { label, dialCode } = props.data;

  return (
    <Option {...props}>
      <div>{label}</div>
      <div>{`( ${dialCode})`}</div>
    </Option>
  );
};

export default function App() {
  const [selected, setSelected] = useState(options[0]);

  return (
    <Select
      options={options}
      value={selected}
      components={{ Option: IconOption }}
    />
  );
}

I use any type in

const IconOption = (props: any) => {
  const { label, dialCode } = props.data;

  return (...);
};

When I set the type of the props to OptionProps, typescript throws error.

const IconOption = (props: OptionProps) => {
  const { label, dialCode } = props.data;

  return (...);
};

enter image description here

How to fix it?

Codesandbox
enter image description here

Codesandbox
https://codesandbox.io/s/react-typescript-forked-mjo74r?file=/src/App.tsx:0-1069

CodePudding user response:

OptionProp is a generic type. You should declare custom type for option's data and pass it to generic.

type OptionData = {
  label: string;
  value: string;
  dialCode: string
}

const options: OptionData[] = [
  {
    label: "label 1",
    value: "value 1",
    dialCode: "dialCode 1"
  },
  {
    label: "label 2",
    value: "value 2",
    dialCode: "dialCode 2"
  }
];

const { Option } = components;

const IconOption = (props: OptionProps<OptionData>) => {
  const { label, dialCode } = props.data;

  return (
    <Option {...props}>
      <div>{label}</div>
      <div>{`( ${dialCode})`}</div>
    </Option>
  );
};

Update 1: the ideomatic way to handle union types in TS is adding type predicates:

function isMultiOption<T>(value: MultiValue<T> | SingleValue<T>): value is T[] {
  return Array.isArray(value)
}

function isSingleOption<T>(value: MultiValue<T> | SingleValue<T>): value is T {
  return value != null && !isMultiOption(value)
}

  const onSelectedChange = (
    newValue: MultiValue<OptionData> | SingleValue<OptionData>
  ) => {
    if (newValue == null) {
      return
    }
    if (isMultiOption(newValue)) {
      setSelected(newValue[0]);
    } else if (isSingleOption(newValue)) {
      setSelected(newValue)
    }
  };
  • Related