You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

React TypeScript报错:Type '() => JSX.Element | undefined' 无法赋值给FC<{}>

React TypeScript类型错误排查与解决

错误信息

Type '() => JSX.Element | undefined' is not assignable to type 'FC<{}>'.
  Type 'Element | undefined' is not assignable to type 'ReactElement<any, any> | null'.
    Type 'undefined' is not assignable to type 'ReactElement<any, any> | null'.ts(2322)

问题原因

  1. 组件返回值可能为undefined:组件首次渲染时,若两个useEffect还未执行,modifiedCocktail处于初始undefined状态,此时第一个if (!modifiedCocktail)和第二个if (modifiedCocktail)都不触发,组件无返回值,不符合FC要求的ReactElement<any, any> | null类型。
  2. 类型定义不匹配:ViewCockTailPros中的ingredients定义为ingredientsProps[](对象数组),但实际代码中赋值的是单个配料字符串/ null组成的数组,类型不兼容。
  3. useState初始值问题:useState<ViewCockTailPros|null>()未指定初始值,默认是undefined,与后续逻辑预期的null/有效数据状态不符。

解决方案

1. 修正useState初始值

将modifiedCocktail的初始值设为null,避免初始状态为undefined:

const [modifiedCocktail, setModifiedCocktail] = useState<ViewCockTailPros|null>(null);

2. 简化组件返回逻辑

去掉第二个冗余的if (modifiedCocktail)判断,第一个if (!modifiedCocktail)已经拦截所有无效状态,后续直接解构即可:

// 移除第二个if判断,直接解构
const { name, image, category, info, glass, instructions, ingredients } = modifiedCocktail;

3. 修正类型定义

调整ViewCockTailPros的ingredients类型为(string|null)[],匹配实际赋值的数组类型,同时移除无用的ingredientsProps类型:

export type ViewCockTailPros = {
  name: string;
  image: string;
  info: string;
  category: string;
  glass: string;
  instructions: string;
  ingredients: (string|null)[];
}

完整修改后的代码

import { FC, useEffect, useState } from "react";
import { useDispatch, useSelector } from "react-redux";
import { Link, useParams } from "react-router-dom";
import { fetchSingleCocktail } from "../redux/features/cocktailSlice";
import { AppDispatch, RootState } from "../redux/store";

export type ViewCockTailPros = {
  name: string;
  image: string;
  info: string;
  category: string;
  glass: string;
  instructions: string;
  ingredients: (string|null)[];
}

const SingleCocktail:FC = () => {
  const { cocktail } = useSelector((state: RootState) => state.app);
  const [modifiedCocktail, setModifiedCocktail] = useState<ViewCockTailPros|null>(null);
  const dispatch = useDispatch<AppDispatch>();
  const { id } = useParams();

  useEffect(() => {
    dispatch(fetchSingleCocktail({id}))
  }, [dispatch, id]);

  useEffect(() => {
    if (cocktail && cocktail.length > 0) {
      const {
        strDrink: name,
        strDrinkThumb: image,
        strAlcoholic: info,
        strCategory: category,
        strGlass: glass,
        strInstructions: instructions,
        strIngredient1,
        strIngredient2,
        strIngredient3,
        strIngredient4,
        strIngredient5
      } = cocktail[0];
      
      const ingredients = [strIngredient1, strIngredient2, strIngredient3, strIngredient4, strIngredient5];
      const newCocktail = { name, image, info, category, glass, instructions, ingredients };
      setModifiedCocktail(newCocktail);
    } else {
      setModifiedCocktail(null);
    }
  }, [cocktail]);

  if (!modifiedCocktail) {
      return <h2 className="section-title">No cocktail to display</h2>
  }

  const { name, image, category, info, glass, instructions, ingredients } = modifiedCocktail;
  return (
      <>
      <section className="section cocktail-section">
              <Link to={"/"}>
                <button className="btn btn-danger" style={{marginTop:"2rem"}}>Go Back</button>
              </Link>
              <h2 className="section-title">{name}</h2>
              <div className="drink">
                <img src={image} alt={name} />
                <div className="drink-info">
                  <p>
                    <span className="drink-data">Name:</span> {name}
                  </p>
                  <p>
                    <span className="drink-data">Category:</span> {category}
                  </p>
                  <p>
                    <span className="drink-data">Info:</span> {info}
                  </p>
                  <p>
                    <span className="drink-data">Glass:</span> {glass}
                  </p>
                  <p>
                    <span className="drink-data">Instructions:</span> {instructions}
                  </p>
                  <p>
                    <span className="drink-data">Ingredents</span> 
                    {ingredients.map((item, index) => {
                      return item ? <span key={index}>{item}</span>:null
                    })}
                  </p>
                </div>
              </div>
      </section>
      </>
    ) 
}

export default SingleCocktail

内容的提问来源于stack exchange,提问作者3gwebtrain

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.19 16:35:23