'Reactjs, typescript

I am trying to make Searchbar where I can fetch the authors and show the author Id and picture, Why I'm getting this error (any Property 'toLowerCase' does not exist on type 'never') in my code?

import { useEffect, useState } from 'react';
import axios from 'axios';

function Searchbar() {
  const [query, setQuery] = useState('');
  const [data, setData] = useState([]);

  // Add one more state to store the authors being searched for

  const [searchResults, setSearchResults] = useState([]);

  useEffect(() => {
    const fetchData = async () => {
      const res = await axios.get(`https://picsum.photos/v2/list`);
      setData(res.data);
    };
    fetchData();
  }, []);

  useEffect(() => {
    setSearchResults(
      data.filter((authorData) =>
        authorData['author'].toLowerCase().includes(query)
      )
    );
  }, [query, data]);

  return (
    <div className='app'>
      <input
        className='search'
        placeholder='Search...'
        onChange={(e) => setQuery(e.target.value.toLowerCase())}
      />
      <div>
        {searchResults.map((author) => (
          <div>{author}</div>
        ))}
      </div>
    </div>
  );
}

export default Searchbar;


Solution 1:[1]

The problem seems to be you are relying on typescript to infer types of an api call. (Instead typescript inferred it as never which would always error if you try anything with it)

To fix this, simply set a type for the fetch data

type fetchData = {
  id: number,
  author: string,
  width: number,
  height: number,
  url: string,
  download_url: string
}

Then set your states as such

const [data, setData] = useState<fetchData[]>([]);
const [searchResults, setSearchResults] = useState<fetchData[]>([]);

Full code

import { useEffect, useState } from "react";
import axios from "axios";

type fetchData = {
  id: number,
  author: string,
  width: number,
  height: number,
  url: string,
  download_url: string
}

function Searchbar() {
  const [query, setQuery] = useState("");

  const [data, setData] = useState<fetchData[]>([]);

  // Add one more state to store the authors being searched for

  const [searchResults, setSearchResults] = useState<fetchData[]>([]);

  useEffect(() => {
    const fetchData = async () => {
      const res = await axios.get(`https://picsum.photos/v2/list`);
      setData(res.data);
    };
    fetchData();
  }, []);

  useEffect(() => {
    setSearchResults(
      data.filter((authorData : fetchData) =>
        authorData.author.toLowerCase().includes(query)
      )
    );
  }, [query, data]);

  return (
    <div className="app">
      <input
        className="search"
        placeholder="Search..."
        onChange={(e) => setQuery(e.target.value.toLowerCase())}
      />
      <div>
        {searchResults.map((author) => (
          <div key={author.id}>{author.author}</div>
        ))}
      </div>
    </div>
  );
}

export default Searchbar;

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1