当与React useState和状态更新函数中的上一个状态一起使用时,如何定义TypeScript类型



我对开发很陌生,需要一些帮助和耐心。我正在将一个React项目转换为TypeScript,在管理和更新Context组件内的状态时遇到了一些问题。

我正在构建一个日志查看器,根据选择的任务显示一系列任务及其嵌套的子任务。

事件在Event类中定义,该类由自定义useFetch钩子中的数据填充。这些作为对象存储在事件数组中。选择任务时,该任务存储在当前的"selectedTask"状态,并且还必须推送到"Hierarchy"数组中。

其想法是当用户单击任务日志的多个嵌套层时,显示随后选择的任务的层次结构。

这些事件在类型"ContextObject"中定义如下:

hierarchy: Event[] | undefined
setHierarchy: Dispatch<SetStateAction<Event[] | undefined>>
selectedSubEvent: Event[];
setSelectedSubEvent: Dispatch<SetStateAction<Event[]>>;

它们通过useState:进行管理

const [hierarchy, setHierarchy] = useState<Event[] | undefined>([]);
const [selectedSubEvent, setSelectedSubEvent] = useState<Event[]>([]);

为了用所选任务更新层次结构,我在useEffect中使用了一个状态更新函数,如下所示,并在"。。。prevState':

useEffect(() => { 
setHierarchy((prevState) => [...prevState, selectedSubEvent])
}, [selectedSubEvent]);

我得到的错误:

Type 'Event[] | undefined' is not an array type.ts(2461)
(parameter) prevState: Event[] | undefined

当我放弃useEffect中的状态更新函数,只将"Hierarchy"设置为"selectedEvent"时,它确实将单个事件设置为层次结构,但显然我需要更多。

我也试过在传播之前检查prevState,但这会出现多个错误:

setHierarchy((prevState) =>
prevState ? [...prevState, selectedSubEvent] : [selectedSubEvent]
);
//Errors
Argument of type '(prevState: Event[] | undefined) => (Event | Event[])[]' is not assignable to parameter of type 'SetStateAction<Event[] | undefined>'.
Type '(prevState: Event[] | undefined) => (Event | Event[])[]' is not assignable to type '(prevState: Event[] | undefined) => Event[] | undefined'.
Type '(Event | Event[])[]' is not assignable to type 'Event[]'.
Type 'Event | Event[]' is not assignable to type 'Event'.
Type 'Event[]' is missing the following properties from type 'Event': key, id, startTime, endTime, and 3 more.ts(2345)

我意识到我没有提供太多我尝试过的东西,但我尝试过无数的文章、教程以及React和TypeScript文档,我不知所措🤷‍♂️

如果我能提供更多信息,请告诉我。如果有人能给我指明正确的方向,我很乐意继续挖掘。


更新

我尝试了@Leigh.D提供的建议,得到了以下结果。

首先:删除"未定义"会导致以下错误:

Argument of type '(prevState: Event[]) => (Event | Event[])[]' is not assignable to parameter of type 'SetStateAction<Event[]>'.
Type '(prevState: Event[]) => (Event | Event[])[]' is not assignable to type '(prevState: Event[]) => Event[]'.
Type '(Event | Event[])[]' is not assignable to type 'Event[]'.
Type 'Event | Event[]' is not assignable to type 'Event'.
Type 'Event[]' is missing the following properties from type 'Event': key, id, startTime, endTime, and 3 more.ts(2345)
(parameter) prevState: Event[]

第二:这也会导致我的上下文提供程序值中的setHierarchy属性出错,但当我从上下文对象中的sethierary中删除"undefined"时,如下所示:

setHierarchy: Dispatch<SetStateAction<Event[]>>

这个错误消失了:

Type 'Dispatch<SetStateAction<Event[]>>' is not assignable to type 'Dispatch<SetStateAction<Event[] | undefined>>'.
Type 'SetStateAction<Event[] | undefined>' is not assignable to type 'SetStateAction<Event[]>'.
Type 'undefined' is not assignable to type 'SetStateAction<Event[]>'.ts(2322)
sub-event-context.tsx(20, 2): The expected type comes from property 'setHierarchy' which is declared here on type 'SubEventContextObject'
(property) setHierarchy: React.Dispatch<React.SetStateAction<Event[] | undefined>>

第三:当我根据FIRST组合删除"未定义"并检查"prevState"时,我得到以下信息:

Argument of type '(prevState: Event[]) => (Event | Event[])[]' is not assignable to parameter of type 'SetStateAction<Event[]>'.
Type '(prevState: Event[]) => (Event | Event[])[]' is not assignable to type '(prevState: Event[]) => Event[]'.
Type '(Event | Event[])[]' is not assignable to type 'Event[]'.
Type 'Event | Event[]' is not assignable to type 'Event'.
Type 'Event[]' is missing the following properties from type 'Event': key, id, startTime, endTime, and 3 more.ts(2345)
(parameter) prevState: Event[]

第四:当我删除选中的"prevState"并对其进行类型转换时,VSCode/Prettier会将其包装在括号中——我不知道这是否是正常行为?

useEffect(() => {
setHierarchy((prevState) => [
...(prevState as Event[]),
selectedSubEvent,
]);
}, [selectedSubEvent]);

除此之外,我也犯了和第三次一样的错误。

解决方案

感谢Leigh.D和Daniel Baldi帮助我解决了这个问题。我似乎有两个问题,他们的两个答案共同纠正了我的错误。任何想要解决类似问题的人,请务必阅读两个答案。

我将Daniel的解决方案标记为公认的答案,主要是因为在我缺乏经验的看来,这是一个更复杂的问题。如果我的想法不正确,请纠正我。

再次感谢您提供的帮助。我真的很感激!

Deon

问题在于您的类型定义(特别是未定义的(以及排列运算符如何解释它。

const [hierarchy, setHierarchy] = useState<Event[] | undefined>([]);

您可以从类型中删除未定义的(因为您无论如何都将状态默认为空数组(,在设置状态或typecast prevState时执行检查,以便排列运算符知道它是一个数组(不是最佳选项(,即:

setHierarchy((prevState) => prevState? [...prevState, selectedSubEvent] : [selectedSubEvent])
setHierarchy((prevState) => [...prevState as Event[], selectedSubEvent])

好吧,我想我已经弄清楚了这里发生了什么。让我们首先考虑一下这里发生了什么:

setHierarchy((prevState) =>
prevState ? [...prevState, selectedSubEvent] : [selectedSubEvent]
);

正如您在ContextObject接口中所述,selectedSubEventEvent的数组,而prevState具有相同类型的hierarchy,因此是Event或未定义的数组。

因此,查看代码,如果prevState的计算结果为truthy值,则创建此[...prevState, selectedSubEvent],它包含prevState的排列,从而产生EventselectedSubEvent,从而产生事件的数组。这是第一个问题,因为得到的值最终是(Event | Event[])[]类型,而它应该是Event[]类型。

prevStatefalsy时,您将hierarchy设置为[selectedSubEvent]。这将创建事件(Event[][](的数组。这是第二个问题!

我可能在这里做错了什么,因为在没有实际运行的情况下尝试编写代码是非常棘手的,但我想尝试一下,它应该会正常工作:

setHierarchy((prevState) =>
prevState ? [...prevState, ...selectedSubEvent] : selectedSubEvent
);

最新更新