2

I created a custom hook to fetch an API and I wanna pass the data to the component and getting this type of error. I'm new to react and typescript

my custom useFetch code:

import { useEffect, useState } from "react";

export interface IBlog {
    data: {
        title: string;
        body: string;
        author: string;
        id: number
        url: string;
    }[]
}
const useFetch = (url: string) => { // url: string

    const [data, setData] = useState<IBlog['data']>([]);
    const [isPending, setIsPending] = useState(false);
    const [error, setError] = useState(null);

    useEffect(() => {
        const abortController = new AbortController();


        setTimeout(() => {
            fetch(url, { signal: abortController.signal })
                .then(res => {
                    if (!res.ok) { // error coming back from server
                        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('fech aborted');
                    } else {
                        // auto catches network / connection error
                        setIsPending(false);
                        setError(err.message);
                    }
                })
        }, 1000);

        // cleanup funtion
        return () => abortController.abort();

    }, [url])

    return [data, isPending, error]
}

export default useFetch

and this is the component where I want to pass the data and getting my error

import BlogList from "./BlogList";
import useFetch from "./useFetch";
import React, { FC } from 'react';
import { IBlog } from "./useFetch"

const Home: FC = () => {

    const [data, isPending, error] = useFetch("http://localhost:8000/blogs")

    console.log(data, isPending, error, "from hook")

    return (
        <div className='home'>
            {error && <div>{error}</div>}
            {isPending && <div>loading...</div>}
            {data && <BlogList data={data} />}
        </div>
    )
}

export default Home

and this is the component to display my data

import BlogList from "./BlogList";
import useFetch from "./useFetch";
import React, { FC } from 'react';
import { IBlog } from "./useFetch"

const Home: FC = () => {

    const [data, isPending, error] = useFetch("http://localhost:8000/blogs")

    console.log(data, isPending, error, "from hook")

    return (
        <div className='home'>
            {error && <div>{error}</div>}
            {isPending && <div>loading...</div>}
            {data && <BlogList data={data} />}
        </div>
    )
}

export default Home

Error messege

    Failed to compile
    C:/Users/63906/Documents/Web Development/citcs-blogs/src/components/Home.tsx
    TypeScript error in C:/Users/63906/Documents/Web Development/citcs-blogs/src/components/Home.tsx(16,26):
    Type 'true | { title: string; body: string; author: string; id: number; url: string; }[]' is not assignable to type '{ title: string; body: string; author: string; id: number; url: string; }[]'.
      Type 'boolean' is not assignable to type '{ title: string; body: string; author: string; id: number; url: string; }[]'.  TS2322
    
        14 |       {error && <div>{error}</div>}
        15 |       {isPending && <div>loading...</div>}
      > 16 |       {data && <BlogList data={data} title='All Blogs!' />}
           |                          ^
        17 |     </div>
        18 |     )
        19 | }
4
  • Can you add json result of that api? Commented Jul 24, 2021 at 7:44
  • { "blogs": [ { "title": "Welcome to UC", "body": "I'm a new student in citcs ", "author": "student", "id": 1 }, { "title": "Enrollment", "body": "first yeat enrollment starts in 2021", "author": "faculty", "id": 2 } ] } this obj in json file Commented Jul 24, 2021 at 8:30
  • Looks like error that types of data that BlogList component expects doesn't match with api response. Need to see BlogList code. Commented Jul 24, 2021 at 8:37
  • Can you try this? export interface IBlog { data: boolean | { title: string; body: string; author: string; id: number url: string; }[] } Commented Jul 31, 2021 at 8:00

1 Answer 1

1

The problem is you're returning a mutable array from useFetch custom hook. And it's type gets inferred as a union of all types of the values it contains:

/*
const useFetch: (url: string) => (boolean | {
    title: string;
    body: string;
    author: string;
    id: number;
    url: string;
}[] | null)[]
*/
const useFetch = (url: string) => {
...
  return [data, isPending, error];
};

To fix the issue you just have to annotate it as a readonly type:

/*
const useFetch: (url: string) => readonly [{
    title: string;
    body: string;
    author: string;
    id: number;
    url: string;
}[], boolean, null]
*/
const useFetch = (url: string) => {
...
  return [data, isPending, error] as const;
};
Sign up to request clarification or add additional context in comments.

1 Comment

Don't like TS for this kinda troubles, type of data defined, but it's not enough.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.