Home > Enterprise >  Getting Object is possibly 'undefined' in typescript react
Getting Object is possibly 'undefined' in typescript react

Time:10-07

I am practicing typescript with react and fetching some data from an API I created a few days ago, API is working fine, am getting data for my front-end while fetching but when I try to use forEach or map method on that array of data it is throwing me an error: Object is possibly 'undefined'

interface Posts {
  _id: string
  title: string
  date: string
  text: string
  author_name: string
  published: boolean
  __v: number
}

const TextField = () => {
  const [posts, setPosts] = useState<Posts>()

  const fetchData = async () => {
    const result = await fetch("https://ed-blog-api.herokuapp.com/api/posts")
    const data = await result.json()
    const posts = data.posts
    setPosts(posts)
  }

  return (
    <div>
      <button onClick={fetchData}>Click</button>
      {posts.forEach((post: object) => {  // getting error here for posts
        console.log(post)
      })}
    </div>
  )
}

CodePudding user response:

Response

{
  "posts": [{
    "_id": "61514ba64209dbbaef9d05bb",
    "title": "Valorant Sucks",
    "date": "2021-09-27T04:40:05.001Z",
    "text": "Valorant Sucks a lot, everytime I got fuccking smurf, not even a single bullet registering and lots of bugs and bugs",
    "author_name": "Dev Chaudhary",
    "published": true,
    "__v": 0
  }]
}

as the response that you used, the response.posts is Array.

so you should do like this.

const [posts, setPosts] = useState<Array<Posts>>([])

Futhermore,

return (
    <div>
      <button onClick={fetchData}>Click</button>
      {posts.forEach((post) => {  // you don't need to use `object` as type.        
        console.log(post)
      })}
    </div>
  )

CodePudding user response:

I think your Posts interface is actually the interface of a single Post

so:

interface Post {
  _id: string
  title: string
  date: string
  text: string
  author_name: string
  published: boolean
  __v: number
}

type Posts=Post[]

Now in here, you don't need to type post as object anymore. Typescript will infer it itself.

    const TextField = () => {
  const [posts, setPosts] = useState<Posts|[]>([])

  const fetchData = async () => {
    const result = await fetch("https://ed-blog-api.herokuapp.com/api/posts")
    const data = await result.json()
    const posts = data.posts
    setPosts(posts)
  }

  return (
    <div>
      <button onClick={fetchData}>Click</button>
      {posts.forEach((post) => {  
        console.log(post)
      })}
    </div>
  )
}

But actually the reason of that error, is that in JavaScript the type of null is also object! so if you type anything as object, you are saying it could be an array, object or null. if it is null, you can't use any properties of it.

CodePudding user response:

Full code

interface Posts {
  _id: string;
  title: string;
  date: string;
  text: string;
  author_name: string;
  published: boolean;
  __v: number;
}

const TextField = () => {
  const [posts, setPosts] = useState<Posts[]>([]);

  const fetchData = async () => {
    const result = await fetch('https://ed-blog-api.herokuapp.com/api/posts');
    const data = await result.json();
    const posts = data.posts;
    setPosts(posts);
  };

  return (
    <div>
      <button onClick={fetchData}>Click</button>
      {posts.map((post: Posts, index: number) => {
        // getting error here for posts
        console.log(post);
        return <div key={index}>{JSON.stringify(post)}</div>;
      })}
    </div>
  );
};

Make posts an array. Then you can solve the loop error.

const [posts, setPosts] = useState<Posts[]>([]);

And I recommend to use map instead of forEach

{posts.map((post: Posts, index: number) => {
    console.log(post);
    return <div key={index}>{JSON.stringify(post)}</div>;
})}

or (If you simply want to output only the component)

{posts.map((post: Posts, index: number) => (
    <div key={index}>{JSON.stringify(post)}</div>
))}
  • Related