Mozamel
Mozamel

Reputation: 67

Error: Property 'title' does not exist on type 'never'. But i see the logs in browser

I got the error:

Property 'title' does not exist on type 'never'. ..... console.log(blog.title);

But at the console of Browser I am able to see the "blog.title".

Here a screenshot from Browser

In this file I use the console.log and recieve the error:

const BlogDetails = () => {
  const { id } = useParams<{ id: string }>();
  const {
    data: blog,
    error,
    isPending,
  } = useFetch("http://localhost:8500/blogs/" + id);

  console.log(blog&& blog.title);
  

  return (
    <div className="blog-details">
      {isPending && <div>loading...</div>}
      {error && <div>{error}</div>}
      {blog && (
        <article>
          <h2>BlogDetails</h2>
        </article>
      )}
    </div>
  );
};

export default BlogDetails;

I use custom hook to fetch the Data:

import { useState, useEffect } from "react";
    
    const useFetch = (url: string) => {
      const [data, setData] = useState(null);
      const [isPending, setIsPending] = useState(true);
      const [error, setError] = useState(null);
    
      useEffect(() => {
        const abortCont = new AbortController();
    
        setTimeout(() => {
          fetch(url, { signal: abortCont.signal })
            .then((res) => {
              if (!res.ok) {
                throw Error("could not fetch the data for that resource");
              }
              return res.json();
            })
            .then((data) => {
              setIsPending(false);
              setData(data);
              setError(null);
            })
            .catch((err) => {
              if (err.name === "AbortError") {
                console.log("fetch aborted");
              } else {
                setIsPending(false);
                setError(err.message);
              }
            });
        }, 1000);
        return () => abortCont.abort();
      }, [url]);
      return { data, isPending, error };
    };
    
    export default useFetch;

Upvotes: 2

Views: 512

Answers (1)

Ori Drori
Ori Drori

Reputation: 192397

Typescript can't infer the types from an api call, so you'll need to provide them explicitly.

However, since useFetch is a generic function, you'll need to add a type that fits the call, and pass it to the internal useState. In addition, the initial value of useState is null, so we should also consider that.

We can add a generic type to useFetch - <T>, and type useState<T | null>() to allow for the intended data type, and null:

export const useFetch = <T>(url: string) => {
  const [data, setData] = useState<T | null>(null);

To use it, you'll need to pass an explicit type to useFetch. For example:

interface Data { 
  title: string;
  body: string;
  author: string;
  id: number;
}

const { data: blog, error, isPending } = useFetch<Data>(
  'http://localhost:8500/blogs/' + id
);

console.log(blog && blog.title); // or just console.log(blog?.title) with optional chaining

Whenever you call useFetch you should provide it with the data type that fits the current response. For example:

useFetch<string[]>( // the result is an array of strings

useFetch<Data[]>( // the result is an array of data objects

useFetch<number>( // the result is a number

Upvotes: 3

Related Questions