Typescript: функция с аргументом типа перечисления, присвоенная обратному вызову с типом аргумента строки - PullRequest
1 голос
/ 05 августа 2020

У меня есть раскрывающийся компонент с обратным вызовом onSelect:(option: string) => void

Я использую его как средство выбора сортировки в одном приложении, где параметры имеют тип перечисления:

enum SORT_OPTIONS {
  LATEST = 'LATEST',
  OLDEST = 'OLDEST'
}
const onSortSelect = (val: SORT_OPTIONS) => {...}
<MyDropdown onSelect={onSortSelect} ... />

И машинописный текст жалуется:

Type '(val: SORT_OPTIONS) => void' is not assignable to type '(option: string) => void'.
  Types of parameters 'val' and 'option' are incompatible.
    Type 'string' is not assignable to type 'SORT_OPTIONS'.  TS2322

Это немного противоречит интуиции, но имеет смысл, поскольку в MyDropdown строка option будет передана в обратный вызов onSortSelect, для которого требуется значение перечисления.

Вопрос как лучше всего исправить типы здесь? IMO обе функции набраны правильно, onSelect должен принимать любую строку, поскольку MyDropdown может использоваться в любом контексте. onSortSelect должен принимать только SORT_OPTIONS.

В настоящее время я использую тип onSortSelect: <MyDropdown onSelect={onSortSelect as (val:string) => void} ... />, но он кажется довольно подробным

Ответы [ 2 ]

0 голосов
/ 06 августа 2020

Мне удалось исправить типы с помощью Generics, без машинописной ошибки

enum SORT_OPTIONS {
  NEWEST='1',
  OLDEST='2'
}

interface DropdownProps<T extends string> {
  onSelect: (val: T) => void;
  options: T[];
}

const Dropdown = <T extends string>(props: DropdownProps<T> & {children?: React.ReactNode}) =>{
  const {onSelect, options} = props;
  return <select onChange={(evt) => onSelect(evt.target.value as T)}>
    {options.map(option => <option>{option}</option>)}
  </select>

};



const TestComp:React.FC = () => {
  const onSelect = (val: SORT_OPTIONS) => {
    switch (val) {
      case SORT_OPTIONS.OLDEST:
        console.log('old');
        break;
      case SORT_OPTIONS.NEWEST:
        console.log('new');
        break;
    }
  };
  const onSelect2 = (val: string) => {
    console.log(val);
  };
  return <>
    <Dropdown
      options={[SORT_OPTIONS.NEWEST, SORT_OPTIONS.OLDEST]}
      onSelect={onSelect}
    />
    <Dropdown
      options={['aaa', 'bbb']}
      onSelect={onSelect2}
    />
    </>
};

Обратите внимание, что

  1. Я не могу набрать Dropdown с обычным React.FC, см. обсуждение здесь: Как использовать дженерики в реквизитах в React в функциональном компоненте?
  2. Мне нужно выполнить приведение типа к типу Generi c.

Прокомментируйте, если найдете другой вывод по ссылке.

0 голосов
/ 05 августа 2020

Ваш обратный вызов имеет дело с onSelect:(option: string) => void

Это означает, что он передает любую строку дескриптору, например: hello, test и т. Д.

Но ваш const onSortSelect = (val: SORT_OPTIONS) => {...} ожидает только подмножество строк: LATEST, OLDEST.

Итак, TypeScript предупреждает вас, что вы не можете передать весь набор функции, которая ожидает подмножество .

Чтобы устранить проблему, вам необходимо обновить обработчик onSelect до:

onSelect:(option: SORT_OPTIONS) => void
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...