user4396386
user4396386

Reputation: 433

Object is possibly 'undefined' error even after checking that object and property exists

I'm getting an Object is possibly 'undefined'. error on every property check and access after story && on the code below. It doesn't make sense to me, since the first check is checking whether story exists, or not. If it didn't exist, wouldn't the ternary just short circuit, and return null? I'm new to typescript (and newish to react). I'd be happy to hear any suggestions! Thanks!

import React, { useState, useEffect } from "react";
import { getStory } from "../services/hnAPI";

interface Props {
  storyId: number;
}

export const Story: React.FC<Props> = (props) => {
  const [story, setStory] = useState();
  useEffect(() => {
    getStory(props.storyId).then((data) => data && data.url && setStory(data));
  }, [props.storyId]);
  return story && story.url ? (
    <a href={story.url}>{story.title}</a>
  ) : null;
};

Upvotes: 4

Views: 6653

Answers (1)

subashMahapatra
subashMahapatra

Reputation: 6837

You should be passing a type argument to useState() so it does not infer the state value as undefined.

Here is an example

import React, { useState, useEffect } from 'react';
import { getStory } from '../services/hnAPI';

interface Props {
  storyId: number;
}

interface Story {
  id: number;
  title: string;
  url: string;
  // properties for the Story
}

export const Story: React.FC<Props> = (props) => {
  const [story, setStory] = useState<Story | null>(null);
  useEffect(() => {
    getStory(props.storyId).then((data: Story) => data && setStory(data));
  }, [props.storyId]);
  return story && story.url ? <a href={story.url}>{story.title}</a> : null;
};

P.S. Please never let a promise get uncatched. If you are making a API call is you getStory function consider adding a catch block and properly handle the error. Example in the same scenario.

export const Story: React.FC<Props> = (props) => {
  const [story, setStory] = useState<Story | null>(null);
  useEffect(() => {
    getStory(props.storyId).then((data: Story) => data && setStory(data))
      .catch(error => {
          // handle the error
          // you can use another state variable to store the error
      });
  }, [props.storyId]);
  return story && story.url ? <a href={story.url}>{story.title}</a> : null;
};

Upvotes: 7

Related Questions