Solucionado (ver solução)
Solucionado
(ver solução)
5
respostas

Argument of type 'string' is not assignable to parameter of type 'SetStateAction<OpcoesOrdenador>'.

Olá, Após fazer as alterações para criar o tipo "OpcoesOrdenador", começou a dar esse erro no Ordenador/index.tsx:

TS2345: Argument of type 'string' is not assignable to parameter of type 'SetStateAction<OpcoesOrdenador>'.
    33 |                 {opcoes.map((opcao => (
    34 |                     <div className={styles.ordenador__option} key={opcao.value}
  > 35 |                         onClick={() => setOrdenador(opcao.value)}
       |                                                     ^^^^^^^^^^^
    36 |                     >
    37 |                         {opcao.nome}
    38 |                     </div>

Eu fiz a alteração pra usar o novo tipo no setOrdenador:

const [ordenador, setOrdenador] = useState<OpcoesOrdenador>("");

Alguém sabe como resolver esse problema?

5 respostas

Fala Hiago, beleza?

Qual seria o tipo de OpcoesOrdenador? Como não tenho o código em mãos não consigo te dar o problema exato, mas pode ser duas coisas:

  • O OpcoesOrdenador não é do tipo string, então o useState não está tipado corretamente (inclusive te recomendo tirar essa tipagem, uma das vantagens do Typescript é a inferência de tipo, então se você coloca o useState com um estado inicial de string, ele vai interpretar como string)

  • O tipo do setState está errado (se ele foi passado como props), o certo seria React.Dispatch<React.SetStateAction<string>> (ou React.Dispatch<React.SetStateAction<OpcoesOrdenador>> caso o OpcoesOrdenador seja do tipo string)

    Caso tenha alguma dúvida sinta-se a vontade para continuar este tópico ou criar um novo, beleza?

    Bons estudos!

Oi, Luiz.

Eu segui as instruções na lição.

Esse é o componente Ordenador:

import styles from './Ordenador.module.scss';
import opcoes from './opcoes.json';
import React, { useState } from 'react';
import classNames from 'classnames';
import { MdKeyboardArrowUp, MdKeyboardArrowDown } from 'react-icons/md';

export type OpcoesOrdenador = '' | 'porcao' | 'qtd_pessoas' | 'preco';
interface Props {
    ordenador: OpcoesOrdenador,
    setOrdenador: React.Dispatch<React.SetStateAction<OpcoesOrdenador>>
}

export default function Ordenador({ ordenador, setOrdenador }: Props) {

    const [aberto, setAberto] = useState(false);
    const nomeOrdenador = ordenador && opcoes.find(opcao => opcao.value === ordenador)?.nome;

    return (
        <button 
            className={classNames({
                [styles.ordenador]: true,
                [styles["ordenador--ativo"]]: ordenador !== ""
            })} 
            onClick={() => setAberto(!aberto)}
            onBlur={() => setAberto(false)}
        >
            <span>{nomeOrdenador || "Ordenar Por"}</span>
            {aberto ? <MdKeyboardArrowUp size={20} /> : <MdKeyboardArrowDown size={20} />}
            <div className={classNames({
                [styles.ordenador__options]: true,
                [styles["ordenador__options--ativo"]]: aberto
            })}>
                {opcoes.map((opcao => (
                    <div className={styles.ordenador__option} key={opcao.value}
                        onClick={() => setOrdenador(opcao.value)}
                    >
                        {opcao.nome}
                    </div>
                )))}
            </div>
        </button>
    )
}

Esse é o componente Cardapio:

import styles from './Cardapio.module.scss';
import { ReactComponent as Logo } from 'assets/logo.svg';
import Buscador from './Buscador';
import { useState } from 'react';
import Filtros from './Filtros';
import Ordenador, { OpcoesOrdenador } from './Ordenador';
import Itens from './Itens';

export default function Cardapio() {
    const [busca, setBusca] = useState("");
    const [filtro, setFiltro] = useState<number | null>(null);
    const [ordenador, setOrdenador] = useState<OpcoesOrdenador>('');

    return (
        <main>
            <nav className={styles.menu}>
                <Logo />
            </nav>
            <header className={styles.header}>
                <div className={styles.header__text}>
                    A casa do código e da massa
                </div>
            </header>
            <section className={styles.cardapio}>
                <h3 className={styles.cardapio__titulo}>Cardápio</h3>
                <Buscador busca={busca} setBusca={setBusca} />
                <div className={styles.cardapio__filtros}>
                    <Filtros filtro={filtro} setFiltro={setFiltro}/>
                    <Ordenador ordenador={ordenador} setOrdenador={setOrdenador} />
                </div>
                <Itens busca={busca} filtro={filtro} ordenador={ordenador} />
            </section>
        </main>
    )
}

O erro aparece no componente Ordenador, nessa linha:

 <div className={styles.ordenador__option} key={opcao.value}
                        onClick={() => setOrdenador(opcao.value)} // Argument of type 'string' is not assignable to parameter of type 'SetStateAction<OpcoesOrdenador>'
                    >

Mas se eu tiro a tipagem do useState, o erro passa pro componente Cardapio:

<Ordenador ordenador={ordenador} setOrdenador={setOrdenador} /> // Type 'string' is not assignable to type 'OpcoesOrdenador'.ts(2322)
index.tsx(9, 5): The expected type comes from property 'ordenador' which is declared here on type 'IntrinsicAttributes & Props'
solução!

Isto provavelmente está acontecendo porque o OpcoesOrdenador tem valores definidos e opcoes.value nunca é tipado, então o Typescript interpreta ele como se fosse string (porque no array de opcoes ele é sempre uma string), então pra isso você tem 2 opções:

  1. tipar o opções e colocar opcoes.value como sendo do tipo OpcoesOrdenador.
  2. forçar o opcoes.value a ser do tipo OpcoesOrdenador na hora do setState, ficando assim: 2.1. `
     onClick={() => setOrdenador(opcao.value as OpcoesOrdenador)} // isto provavelmente vai funcionar pra você

Tentei a segunda opção e funcionou.

Obrigado!

Eu estava com o mesmo problema. Valeu pela solução.