React/Typescript: The object might be null

I am currently converting a React component to TypeScript. The component is making an API call, and although I believe my interfaces are correctly set up, I seem to be passing the types incorrectly.

How can I resolve the two errors in the Parent component below?


  • return <div>Error: {error.message}</div>; // "Object is possibly 'null'"

  • {stories.results.map((story, idx) => { // "Object is possibly 'null' or 'undefined'"

  • alt={  // Type 'string | null' is not assignable to type 'string | undefined'. Type 'null' is not assignable to type 'string | undefined'.

My Interfaces


export interface NewsProps {
  results?: (ResultsEntity)[] | null;
}
export interface ResultsEntity {
  section: string;
  title: string;
  abstract: string;
  url: string;
  multimedia?: (MultimediaEntity)[] | null;
}
export interface MultimediaEntity {
  url: string;
  caption: string;
  alt:string;
}

Parent Component


import React, { FC, ReactElement, useEffect, useState } from "react";
import Story from "./Story";

const News: FC<NewsProps> = ({results:ResultsEntity}):ReactElement => {
  const [error, setError] = useState(null);
  const [stories, setStory] = useState<NewsProps>();

  useEffect(() => {
    const getCurrentPage = () => {
      const url = new URL(window.location.href);
      const page = url.pathname.split("/").pop();
      return page ? page : "home";
    };

    const section = getCurrentPage();

    fetch(
      `https://api.nytimes.com/svc/topstories/v2/${section}.json?api-key=4fzCTy6buRI5xtOkZzqo4FfEkzUVAJdr`
    )
      .then((res) => res.json())
      .then((data) => {
        setTimeout(() => setStory(data), 1500);
      })
      .catch((error) => {
        setError(error);
      });
  }, []);

  if (error) {
    return <div>Error: {error.message}</div>; // "Object is possibly 'null'"
  } else 
  if (!stories) {
    return <div>Loading...</div>
  } else {
    return (
      <>
        <ul className="stories">
          {stories.results?.map((story, idx) => {  
            return (
              <Story
                key={idx}
                title={story.title}
                abstract={story.abstract}
                img={story.multimedia![0].url}
                alt={story.multimedia && story.multimedia[0]?.caption ? story.multimedia[0].caption! : ''}
                link={story.url}
              />
            );
          })}
        </ul>
      </>
    );
  }
}
export default News;

Child


import React, { FC, ReactElement } from "react";

interface StoryProps {
  title?: String;
  img?: string;
  alt?: string;
  abstract?: string;
  link?: string;
}

const Story: FC<StoryProps> = ({title, img, alt, abstract, link}): ReactElement => {
  return (
    <div className="story">
      <li className="story-title">{title}</li>
      <span className="story-content">
        <img className="story-img" src={img} alt={alt} />
        <span>
          <li className="story-body">{abstract}</li>
        </span>
      </span>
    </div>
  );
};
export default Story;

Answer №1

When dealing with the error variable, it's important to specify a type when creating the state. If you pass in null without specifying a type, TypeScript will infer that the state is always null:

const [error, setError] = useState(null);

If you have some information about the error, you can declare a type that represents it, like this:

const [error, setError] = useState<null | { message: string }>(null);

If you don't have any information, using any might be necessary:

const [error, setError] = useState<any>(null);

Regarding the stories, the .results property is allowed to be null or undefined according to its interface:

export interface NewsProps {
  results?: (ResultsEntity)[] | null;
}

Make sure to check for these values before utilizing them. For example, you can skip the map statement and render nothing if needed:

{stories.results && stories.results.map((story, idx) => {

You can also use optional chaining for similar functionality (requires TypeScript 3.7 or later):

{stories.results?.map(story, idx) => {

In terms of the alt prop, avoid passing in null as it isn't valid. Use undefined instead:

alt={
  story &&
  story.multimedia &&
  story.multimedia[0] &&
  story.multimedia[0].caption
    ? story.multimedia[0].caption
    : undefined
}

Alternatively, utilize optional chaining for a concise approach:

alt={story?.multimedia?.[0]?.caption}

Answer №2

Utilize the Optional Chaining operator ("?") for both scenarios.

<div>Error: {error?.message}</div>;

 // Similar to ( check if error is present then access the property on it )
 <div>Error: {error && error.message}</div>;
<ul className="stories">
      {stories.results?.map((story, idx) => {
        return (
          <Story
            key={idx}
            title={story.title}
            abstract={story.abstract}
            img={story.multimedia[0].url}
            alt={story.multimedia[0].caption}
            link={story.url}
          />
        );
      })}
    </ul>

NOTE - In the second case I am putting "?", as in your interface "NewsProps," the results property can be undefined or null.

Ref: https://www.typescriptlang.org/docs/handbook/release-notes/typescript-3-7.html#optional-chaining

-- After edit --

  • The alt issue arises from expecting the alt type in the Story component as "string" or "undefined" (when adding "?"). To resolve this, replace null with an empty string "" at the end of the parent checks.
interface StoryProps {
  title?: String;
  img?: string;
  alt?: string; // -> This is now a string | undefined type
  abstract?: string;
  link?: string;
}

 <Story
   key={idx}
   title={story.title}
   abstract={story.abstract}
   img={story.multimedia[0].url}
   alt={ 
    story &&
    story.multimedia && 
    story.multimedia[0] &&
    story.multimedia[0].caption 
    ? story.multimedia[0].caption 
    : "" // -> Use "" instead of null here
   }
    link={story.url}
 />

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Removing padding from Material UI Container when width is xs can be achieved by adjusting the CSS properties accordingly

When the size of Container changes to xs, I want it to have zero padding. I attempted to achieve this using the following code snippet from https://material-ui.com/api/container/, but so far, I haven't been successful. When I replace maxWidthXs with ...

Error message: Unable to access the state property of an undefined object

I've been attempting to integrate a react sticky header into my stepper component. However, I've encountered an issue where it doesn't render when added inside my App.js file. As a result, I've started debugging the code within App.js ...

Selecting an option with a specific index in Angular 2 RC2

I have encountered a situation where the select options are non-unique, with the same value representing different things. This is how our data is structured and I need to work within those constraints. <select id="mySelect"> <option value = "1 ...

Centering items in Material UI Grid

I'm currently grappling with understanding Material UI's grid system and implementing it in React.js, and I find it a bit perplexing. My goal is to center the spinner loader and text irrespective of viewport size. While I can manage to place the ...

What is the correct way to configure an API request utilizing the useEffect hook in React?

I have encountered an issue with my component where the correct data is showing up in the console under "data", but when attempting to run a map function on it, I am receiving an error message stating that "map is not a function." The console shows 16 item ...

While attempting to index a nested object, TypeScript (error code 7053) may display a message stating that an element implicitly carries the 'any' type due to the inability to use an expression of type X to index type

I'm encountering an issue in TypeScript where I get the error (7053): Element implicitly has an 'any' type because expression of type X can't be used to index type Y when trying to index a nested object. TypeScript seems to struggle wit ...

Trouble accessing setState within an axios call in ReactJs

I've encountered an issue while attempting to set the state of the variable isCorrectAnswer within an axios call. The error message Cannot read properties of undefined (reading 'setState') is showing up in the console log. What mistake am I ...

"Implementing responsive design with Material-UI components in React using

It has become quite annoying to constantly see all these warnings related to DOMNesting. No matter what I do, I can't seem to get rid of them completely. Here is a typical example: Warning: validateDOMNesting(...): <table> cannot appear as a des ...

React Native: Enhance the background with a vibrant stripe of color

I am trying to incorporate a strip of grey in the middle of my white background, but I am encountering an issue where I am unable to input any text inside it. Below is the code snippet I am working with: container: { flex: 1, justifyContent: "cent ...

Angular Material: Enhanced search input with a universal clear button

After searching for a cross-browser search control with a clear button similar to HTML5, I found the solution rendered by Chrome: <input type="search> The code that gave me the most relevant results can be found here. I used the standard sample w ...

Encountering the error "props.children is throwing a function" while trying to publish my Gatsby website

I've checked out other posts related to this issue but still can't seem to resolve it. My development build is functioning properly, but the error below is being thrown by Netlify during deployment: 4:58:48 PM: WebpackError: TypeError: props.ch ...

Can cells be divided in a Material UI table?

Is there a way to split a cell in a Material UI table?I am aware that I can create a component to achieve this, but I'm wondering if there is another approach that I may not be aware of. Splitting a cell means having two values separated by a line wit ...

Be warned: Babel has detected a duplicate plugin or preset error

Currently, I am enrolled in a React course on Frontend Masters. As part of the course, we were tasked with modifying the Babel config to allow state instantiations like: state = {index: 0} in class components. However, when I executed the command: npm i ...

The pagination in the DataGrid is not aligning correctly to the right when placed within a container with the "rtl" direction attribute

I'm struggling to set up a DataGrid with pagination using Material-UI within a container that has dir="rtl". Despite customizing the pagination component to align to the right side of the container, it doesn't seem to be working correctly. Take ...

Tips for adding and verifying arrays within forms using Angular2

Within my JavaScript model, this.profile, there exists a property named emails. This property is an array composed of objects with the properties {email, isDefault, status}. Following this, I proceed to define it as shown below: this.profileForm = this ...

Parent component experiencing delays while updating React state

As I work on my react application, I've always believed that state updates in react happen quickly. However, I've come across a problem recently. In one of the pages of my application, there are multiple elements present. One particular element ...

What is the process of creating a new array by grouping data from an existing array based on their respective IDs?

Here is the initial array object that I have: const data = [ { "order_id":"ORDCUTHIUJ", "branch_code":"MVPA", "total_amt":199500, "product_details":[ { ...

TypeScript has encountered an issue where a specific type A cannot be assigned to another type A, even though

Encountering a Typescript issue where it claims that type A is not compatible with type A, even though they are identical: Check out this playground link for the code snippet in context: declare interface ButtonInteraction { user: any; customId: strin ...

How to set up Angular 5 with Express

What is the best way to add Angular 5 to an existing Express project? Below are my files: https://i.stack.imgur.com/DPgMs.png Package.json: https://i.stack.imgur.com/iVVxA.png I am looking to integrate Angular 5 into this express project and develop t ...

React: Material UI, Counting All the Rows

How many rows does Material UI in REACT support in its free and paid versions? I have a massive dataset exceeding 400 MB. Is this realistic or too ambitious? ...