reactjs - 打字稿/反应:“对象可能是‘空’”
问题描述
我正在将 React 组件更改为 Typescript。它调用一个 API。我相信我的接口设置正确,但我没有正确传递类型。
如何修复下面父级中的两个错误?
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'.
我的界面
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;
解决方案
对于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
,但这不是 . 的合法值alt
。undefined
而是通过。
alt={
story &&
story.multimedia &&
story.multimedia[0] &&
story.multimedia[0].caption
? story.multimedia[0].caption
: undefined
}
或使用可选链接:
alt={story?.multimedia?.[0]?.caption}
推荐阅读
- javascript - 带有 ref 的 useEffect 显示以前的状态而不是最新的
- html - 尝试将文本添加到网格
- javascript - 获取嵌套对象结构字段的所有排列
- c# - 用于创建 MediaSource 的 MP3 内容类型
- ruby - Where should I put custom error classes when creating a new library?
- html - 使用媒体查询更改网格
- java - 当一个注入的依赖项需要同一类中的 bean 时,Spring 不会填充其他变量
- java - 无法从 com.google.android.exoplayer2.upstream.ResolvingDataSource 中找到符号“ResolvingDataSource”
- javascript - D3 散点图变换符号
- c# - 如何多次获取变量字符串和常量字符串之间的字符串