首页 > 解决方案 > 打字稿/反应:“对象可能是‘空’”

问题描述

我正在将 React 组件更改为 Typescript。它调用一个 API。我相信我的接口设置正确,但我没有正确传递类型。

如何修复下面父级中的两个错误?



我的界面


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;
}

父组件


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) => {  // "Object is possibly 'null' or 'undefined'"
            return (
              <Story
                key={idx}
                title={story.title}
                abstract={story.abstract}
                img={story.multimedia[0].url}
                alt={  // Type 'string | null' is not assignable to type 'string | undefined'. Type 'null' is not assignable to type 'string | undefined'.
                  story &&
                  story.multimedia &&
                  story.multimedia[0] &&
                  story.multimedia[0].caption
                    ? story.multimedia[0].caption
                    : null
                }
                link={story.url}
              />
            );
          })}
        </ul>
      </>
    );
  }
}
export default News;

孩子


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;

标签: reactjstypescriptfetchreact-typescript

解决方案


对于error,问题是当你创建状态时,你没有明确地给它一个类型,所以打字稿必须尝试推断类型。它看到你传入了 null,所以它假设状态是(并且永远是)null

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

如果您知道错误将是什么,您可以给出一个表示该错误的类型。例如:

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

如果你什么都不知道,那么你可能需要求助于any

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

对于stories,您已将.results属性定义为可能为 null 或未定义:

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

...但是您在使用它之前不会检查这些值。您需要编写代码来检查这些情况。例如,如果您只想跳过 map 语句并且不渲染任何内容,您可以这样做:

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

或者与可选链接相同的东西(需要 typescript 3.7 或更高版本):

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

对于alt道具,您正在传递null,但这不是 . 的合法值altundefined而是通过。

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

或使用可选链接:

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

推荐阅读