我正在将 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;
答案 0 :(得分:2)
对于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}
答案 1 :(得分:0)
对于这两种情况,您都可以使用“?”运算符(可选链)。
<div>Error: {error?.message}</div>;
// This is 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>
注意 - 在第二种情况下,我输入“?”在结果前面,原因是在您的界面中“NewsProps”结果属性可以是未定义的或空的。
参考:https://www.typescriptlang.org/docs/handbook/release-notes/typescript-3-7.html#optional-chaining
-- 修改后--
interface StoryProps {
title?: String;
img?: string;
alt?: string; // -> This is the one string | undefined
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
: null // -> here use "" instead of null
}
link={story.url}
/>