Как использовать Symbol.iterator с машинописным текстом

#javascript #reactjs #typescript #react-hooks

Вопрос:

Я переписываю свое старое приложение, написанное на React JavaScript, в React Typescript. В моем старом приложении код, который я пытаюсь повторно использовать, работал отлично, но TS это не нравится, и я не уверен, почему — я также впервые использую TS.

Я экспортирую свой тип данных:

 export type CartItemType = { 
.....
id: number;
name: string;
.....
}
 

И получение моих карт и данных с помощью крючков

  const [cartItems, setCartItems] = useState([] as CartItemType[]);
 const { data, isLoading, error } = useQuery<CartItemType[]>(
            'products',
            getProducts
        );
 

Я сопоставляю данные, как обычно

 data?.map((item) => {
        return (
......
)}
 

Теперь каждый из моих объектов данных имеет разные варианты цветов, и я хотел бы иметь возможность переключаться между ними.

Это мой подход:

 function handleColorChange(e) {
        e.preventDefault();
        let newData = [...data];
        let changedItem = {
            ...data.find((i) => i.name === selectedData.name),
        };
        let changedItemIndex = data.findIndex(
            (i) => i.name === selectedData.name
        );
        changedItem.chair.selected = e.target.value;
        newData[changedItemIndex] = changedItem;
        setSelectedColor(newData);
    }
 

Чтобы объяснить приведенный выше код, я пытаюсь обрабатывать каждое изменение цвета, где selectedData указаны только данные о выбранном продукте и chair.selected значение цвета по умолчанию для конкретного продукта.

Я сопоставляю все цвета конкретного продукта с моим объектом данных

 {Object.values(selectedData.chair.colors).map(
 (key) => {
           return (
              <ItemButtonChair hex={key.hex} name={key.name} image={key}
                              click={handleColorChange}
               ></ItemButtonChair>
           );})}
 

ItemButtonChair изготовлен мной на заказ

 function ItemButtonChair(props) {
    let colorHeaderClassName = `selected ${props.click}`;

    return (
        <input
            type="button"
            value={props.name}
            name={props.name}
            onClick={props.click}
            className={colorHeaderClassName}
            style={{
                backgroundColor: props.hex,
                color: props.hex,
            }}
        />
    );
}
 

Когда я пытаюсь запустить этот подход, я обнаруживаю ошибку Type 'CartItemType[] | undefined' must have a '[Symbol.iterator]()' method that returns an iterator. , я пытался найти в Google, как это исправить, но, похоже, каждый случай с этой ошибкой очень обычен, и я просто не понимаю, почему TS это не нравится.

Ответ №1:

Ошибка типа на самом деле говорит вам о проблеме: тип data is CartItemType[] | undefined , поэтому он может быть undefined , который вы не можете повторить. Хотя, поскольку у вас нет отслеживания или указания на него, я не знаю, что ...data его вызывает и есть ли у него типовая защита или что-то в этом роде.

Если вы уверены data , что на данный момент он существует, вы можете использовать ...data! , чтобы сказать TypeScript «Я уверен, что это не null / undefined «.

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

1. Спасибо @KelvinSchoofs, ошибка указывает data на handleColorChange функцию. Я не знаю, как они могут быть неопределенными, так как я сопоставляю их и получаю свои объекты нормально. Я уже пробовал использовать ...data! , но это все еще кажется неправильным, с тех пор changedItem.chair.selected он недокормлен…и я действительно не знаю, почему

2. Ты звонишь handleColorChange изнутри карты? TypeScript не понимает, что handleColorChange он вызывается только тогда, когда data установлен, поэтому он возвращается к ... | undefined функции. Изменения data в data! пределах этой функции должно быть достаточно. Что-то подобное может произойти changedItem.chair.selected и с вами . Если вы уверены, что эти поля существуют, вы можете сделать, например changedItem.chair!.selected .

Ответ №2:

Я нашел решение, которое работает, вероятно, это не очень хорошая практика, чтобы делать это таким образом, поэтому я не буду отмечать это как решение, но оно работает!

Таким образом, в основном вместо одного состояния я создаю больше для каждого объекта, который у меня есть.

selectedColor1 , selectedColor2 , ……

И в handleColorChange настройке функции для каждого состояния:

 setSelectedColor1(newData[0]);
setSelectedColor2(newData[1]);
............
 

Я могу достичь того, что мне было нужно с помощью этого подхода, и цвета каждого объекта обновляются по щелчку мыши.