React+TypeScript中useReducer状态更新类型错误排查求助
React useReducer状态赋值类型不匹配问题
问题代码与错误信息
自定义Hook代码
import React, { useReducer, useEffect } from 'react'; import { v4 as uuid } from 'uuid'; import { Movie, MoviesAction } from 'types'; import { getMovies } from 'api/movies'; interface MoviesState { movies: Movie[] initialized: boolean } export function useMoviesCollection(): [MoviesState, React.Dispatch<MoviesAction>] { const movieReducer = (state: MoviesState, action: MoviesAction): MoviesState => { switch (action.type) { case 'fetch': return { ...state, movies: action.payload }; case 'add': return { ...state }; case 'delete': return { ...state }; case 'rate': return { ...state }; default: return state } }; const [state, dispatch] = useReducer(movieReducer, { movies: [], initialized: false, }); useEffect( () => { getMovies().then((d)=>{ dispatch({ type: 'fetch', payload: { data: d } }) }) }, []); return [state, dispatch]; }
API实现
import { Movie } from "types" export const getMovies = async (): Promise<Movie[]> => { return require('../data/movies.json') }
类型定义
export interface Movie { id: string, title: string, subtitle: string, description: string, imageUrl: string, ratings: number[] } export interface MovieFetchAction { type: 'fetch', payload: { data: Movie[] } }
错误信息
Type '{ data: Movie[]; }' is missing the following properties from type 'Movie[]': length, pop, push, concat, and 28 more.
错误原因
在movieReducer的fetch分支中,你尝试将action.payload直接赋值给state.movies,但根据MovieFetchAction的定义,action.payload是包含data字段的对象(类型为{ data: Movie[] }),而state.movies需要的是Movie[]类型,两者类型不匹配,触发TypeScript类型检查错误。
修复方案
两种可行修复方式任选其一:
方案1:修改reducer逻辑,提取payload中的data
直接在reducer里获取action.payload.data赋值给movies,同时可将initialized设为true标记数据加载完成:
case 'fetch': return { ...state, movies: action.payload.data, initialized: true };
方案2:简化Action的payload类型
如果不需要嵌套的data字段,可调整类型定义和dispatch传参:
- 修改
MovieFetchAction的payload类型:
export interface MovieFetchAction { type: 'fetch', payload: Movie[] }
- 调整useEffect中的dispatch代码:
getMovies().then((d)=>{ dispatch({ type: 'fetch', payload: d }) })
- reducer中的
fetch分支保持原逻辑即可:
case 'fetch': return { ...state, movies: action.payload, initialized: true };
内容的提问来源于stack exchange,提问作者krickht
相关产品推荐
相关产品推荐

