Выберите тип из одного из реквизитов

#reactjs #typescript

Вопрос:

У меня есть компонент списка

 type Option = {
  id: string;
};

type Props<O> = {
  options?: O[];
  option?: JSXElementConstructor<O>;
};

const List = <O extends Option>(props: Props<O>) => ...
 

и некоторые дополнительные компоненты, такие как этот

 type Props = {
  label: string;
  icon?: ElementType;
  onClick?: () => void;
};

const BasicOption = (props: Props) => ...
 

чтобы получить правильный тип, я должен сделать это

 const Example = () => {
  const options = [
    { id: 'a', label: 'Label A', icon: PlaceholderIcon },
    { id: 'b', label: 'Label B', icon: PlaceholderIcon },
    { id: 'c', label: 'Label C', icon: PlaceholderIcon },
    { id: 'd', label: 'Label D', disabled: true },
    { id: 'e', label: 'Label E' },
  ];

  return (
    <List<typeof options[number]>
      options={options}
      option={BasicOption}
    />
  );
};
 

есть ли способ получить правильный ввод непосредственно из массива, чтобы избежать <typeof options[number]> части?

Рабочий пример: https://codesandbox.io/s/vigorous-hopper-i41uj?file=/src/App.tsx

Комментарии:

1. Пожалуйста, поделитесь воспроизводимым примером. JSXElementConstructor , ElementType ? Это будет лучшее, что вы можете сделать, поделившись им на игровой площадке TS

2. @капитан-йоссариан закончил!

Ответ №1:

Вам нужно сделать вывод options и связать его option .

 import React, { JSXElementConstructor, ElementType } from "react";


export type BasicProps = {
  label: string;
  icon?: ElementType;
  onClick?: () => void;
};

export const BasicOption = ({ label, icon: Icon, onClick }: BasicProps) => (
  <div onClick={() => onClick?.()}>
    {label}
    {Icon amp;amp; <Icon />}
  </div>
);


export type Option = {
  id: string;
};

export const List = <Opt extends Option, Options extends Opt[]>({
  options,
  option: Option
}: {
  options: [...Options],
  // same as typeof options[number] but Options is infered
  option: JSXElementConstructor<[...Options][number]>;
}) => (
  <div>
    {Option amp;amp;
      options amp;amp;
      options.map((option) => <Option key={option.id} {...option} />)}
  </div>
);

export default function App() {
  const options = [
    { id: "a", label: "Label A" },
    { id: "b", label: "Label B" },
    { id: "c", label: "Label C" },
    { id: "d", label: "Label D", disabled: true },
    { id: "e", label: "Label E" }
  ];

  return (
    <List options={options} option={BasicOption} />
  );
}
 

Игровая площадка

Вы можете найти больше о выводе аргументов функций в моем блоге

Комментарии:

1. TS может сделать вывод об этом из […Вариантов][числа], отлично!