Добавление интерфейсов Typescript для глубоко вложенных объектов, возвращаемых API

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

export default function AnimalAdoptionCosts() {
  const [currencyQuote, setCurrencyQuote] = useState({});
  const [userInput, setUserInput] = useState("");

    const fetchAdoptionRates = async (userInput: string) => {
    const response = await fetch(
      `http://localhost:5000/v1/adoptionRate?animal=${userInput}`
    );
    console.info(response);
    const body = await response.json();
    if (response.status !== 200) throw Error(body.message);
    setCurrencyQuote(body);
  };


  const handleSubmit = async (userInput: string) => {
    await fetchExchangeRates();
    const costToAdopt = currencyQuote?.data.quote.USD.price;
  };

  return (
    <>
      <form onSubmit = {() => handleSubmit(userInput)}>
        <label htmlFor = "animal">Enter an animal type</label>
        <input
          value = {userInput}
          id = "userinput"
          placeholder = "ex: Pomeranian"
          onChange = {(event) => setUserInput(event.target.value)}
        />
        <input type = "submit" value = "Submit" />
       {costToAdopt}
      </form>
    </>

Ошибка Typescript: [1] Property 'data' does not exist on type '{}'. TS2339 для этой строки: const costToAdopt = currencyQuote?.data.quote.USD.price;

Я понимаю, что это потому, что useState устанавливает значение по умолчанию как пустой объект, но это странно.

interface CurrencyQuote {
 data: {
    quote:  {
       USD:   {
         price: number
       }
    }
}

это то, что я должен делать? Я нашел эту примерную игровую площадку для работы, но тогда я бы сделал 4 разных интерфейса, что кажется слишком сложным.

Кроме того, если вы гений TS, я бы хотел помочь выяснить, как вводить другую важную информацию в моей функции. Спасибо!

Первое, что я замечаю, это то, что нет причин для adoptionRates сохранять состояние, если только вы не используете его где-то еще?

Nick 21.12.2020 03:02

@Ник, хорошая мысль, я понял, упрощая свой код, я испортил имена некоторых переменных, теперь это currencyQuote, и после установки costToAdopt я хочу отобразить результат

stonerose036 21.12.2020 03:20

Даже с учетом этого изменения переменной, я думаю, вы правы в том, что ей не нужно сохранять состояние, я, вероятно, могу просто вернуть costToAdopt в fetchAdoptionRates fn

stonerose036 21.12.2020 03:22

При всем при этом я по-прежнему считаю, что в целом стоит написать полную типизацию для возвращаемого типа данных. Это дает вам все преимущества TS!

Nick 21.12.2020 03:23
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Навигация по приложениям React: Исчерпывающее руководство по React Router
Навигация по приложениям React: Исчерпывающее руководство по React Router
React Router стала незаменимой библиотекой для создания одностраничных приложений с навигацией в React. В этой статье блога мы подробно рассмотрим...
Массив зависимостей в React
Массив зависимостей в React
Все о массиве Dependency и его связи с useEffect.
0
4
570
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Если вам нужно только costToAdopt, я бы рекомендовал просто сохранить это значение отдельно в вашем useState в виде числа. Это значительно упрощает набор текста, и вы можете избежать вложения.

const [costToAdopt, setCostToAdopt] = useState<number>(0);

// ...

const fetchAdoptionRates = async (userInput: string) => {
  const response = await fetch(
    `http://localhost:5000/v1/adoptionRate?animal=${userInput}`
  );
  console.info(response);
  const body = await response.json();
  if (response.status !== 200) throw Error(body.message);
  setCostToAdopt(body?.data?.quote?.USD?.price || 0);
};

// ...

Спасибо! Это очень помогло и упростило некоторые вещи. Я пошел дальше и добавил подобные типизации ко всем моим функциям useState. const [cryptos, setCryptos] = useState<Object>({}); const [conversionRateToUSD, setConversionRateToUSD] = useState<число>(0); const [userInput, setUserInput] = useState<string>(""); Есть ли что-то еще, что я должен сделать с точки зрения интерфейсов?

stonerose036 21.12.2020 03:42

Вместо ввода Object вместо cryptos я бы создал интерфейс с ключами, которые вы будете использовать в криптографии, и использовал бы его, чтобы вы могли получить доступ к свойствам без ошибок типа.

Todd Skelton 21.12.2020 03:53

Другие вопросы по теме