我正在将我的 React 应用程序重构为 Typescript,到目前为止一切顺利。我在我的最后一个组件上,那个获取 API 数据的组件,我试图理解为什么这些类型错误没有解决。我使用 https://jvilk.com/MakeTypes/ 来帮助正确搭建接口。
Object is possibly 'null'
两次用于 error
和 stories
(下面的注释行)
Parameter '___' implicitly has an 'any' type.
两次用于 story
和 idx
(下面的注释行)
我在使用此 API 调用组件时遇到问题。我错过了什么?
import React, { FC, ReactElement, useEffect, useState } from "react";
import Story from "./Story";
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;
}
const News: FC<NewsProps> = ({results:ResultsEntity}):ReactElement => {
const [error, setError] = useState(null);
const [stories, setStory] = useState(null);
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) => {
console.log("Error", error);
setError(error);
});
}, []);
if (error) {
return <div>Error: {error.message}</div>; /// "Object is possibly 'null'" (for error)
} else
if (!stories) {
return <div>Loading...</div>
} else {
return (
<>
<ul className="stories">
{stories.results.map((story, idx) => { // "Object is possibly 'null'" (for stories)
// Parameter '__' implicitly has an 'any' type (for idx & story)
return (
<Story
key={idx}
title={story.title}
abstract={story.abstract}
img={
story &&
story.multimedia &&
story.multimedia[0] &&
story.multimedia[0].url
? story.multimedia[0].url
: null
}
alt={
story &&
story.multimedia &&
story.multimedia[0] &&
story.multimedia[0].caption
? story.multimedia[0].caption
: null
}
link={story.url}
/>
);
})}
</ul>
</>
);
}
}
export default News;
答案 0 :(得分:0)
在您的代码中,有两个地方 TS 编译器不知道某些值的确切类型,并警告您您已尝试对它们执行(可能)无效的操作。
添加 | null
也无济于事,因为这不是问题的原因,而添加 (unless you are using the --strictNullChecks
flag) null
is assignable to any type by default,因此无需输入。
问题点:
error.message
尽管您检查了 error
的真实性,但编译器无法推断它不可能是 null
。而且,当然,访问 null
上的属性会出错,因此会发出警告。
要解决这个问题,您可以使用non-null assertion operator:
error!.message
stories
由于该值是根据网络请求动态设置的,因此 TS 不会知道它的类型(它无法从默认值推断它,因为它是 null
)。这导致它是 any
,并且编译器也不知道对它的操作(例如它不知道 .map()
是 Array#map()
,所以也不知道类型它将传递给其回调的参数)。
要解决此问题,您必须定义 stories
的确切类型(接口)(及其属性,递归)。然后,将该接口传递给 useState
,以定义状态变量的类型。
但是,由于 stories
有时也是 null
,因此在正确定义其类型后,您必须在访问属性之前使用非空断言,其推理与上述相同。>
总而言之,您的代码应如下所示:
import React, { FC, ReactElement, useEffect, useState } from "react";
import Story from "./Story";
export interface NewsProps{
//Props of the component go here
//Don't confuse them with state or other variables
}
interface Result {
results: ResultsEntity[];
}
interface ResultsEntity {
section: string;
title: string;
abstract: string;
url: string;
multimedia?: MultimediaEntity[];
}
interface MultimediaEntity {
url: string;
caption: string;
}
const News:FC<NewsProps> = ():ReactElement => {
const [error, setError] = useState<Error | null>(null);
const [stories, setStory] = useState<Result | null>(null);
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) => {
console.log("Error", error);
setError(error);
});
}, []);
if (error) {
// v-- Non-null assertion (it can't be null, you've checked beforehand)
return <div>Error: {error!.message}</div>;
} else
if (!stories) {
return <div>Loading...</div>
} else {
return (
<>
<ul className="stories">
// v-- Non-null assertion (it can't be null, you've checked beforehand)
{stories!.results.map((story, idx) => {
return (
<Story
key={idx}
title={story.title}
abstract={story.abstract}
img={
// vv-- It's enough to do this (optional chaining, new JS feature). Much more readable. See https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Optional_chaining
story.multimedia?.[0].url ?? null
// ^^^^^^^^^^^ ^^^^-- Fallback value
// +++++++++++-- Thing that may be null or undefined
}
alt={
story.multimedia?.[0].caption ?? null //Same as above
}
link={story.url}
/>
);
})}
</ul>
</>
);
}
}
export default News;
See it live 在 TS Playground 中(不会产生错误)
答案 1 :(得分:0)
打字稿不理解null
的类型
const [error, setError] = useState<string>(null);