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

NextJS+TypeScript项目中使用forwardRef遇类型错误求解决

修复NextJS+TypeScript中forwardRef的类型错误

我在NextJS+TypeScript项目中拥有一个添加商品到购物车的表单,该表单是独立组件,使用forwardRef时出现了类型错误。

forwardRef错误截图

当前组件代码

Food.tsx组件

import Image from "next/image";
import Link from "next/link";
import React, { FormEvent, Key, useRef } from "react";
import { FiPlus } from "react-icons/fi";
import { useDispatch } from "react-redux";
import useAddItemToCart from "../hooks/useAddItemToCart";
import { addItemToCart } from "../store/cartSlice";
import FoodForm from "./FoodForm";

const Food: React.FC<{
  id: Object;
  title: String;
  desc: String;
  price: Number;
  kit: Boolean;
  category: String;
  ingredients: Array<string>;
  image: String;
  index: Key;
}> = ({ id, title, desc, price, kit, category, index, ingredients, image }) => {
  const amountInputRef = useRef<HTMLInputElement>(null);
  const { handlerAddItemToCart: handlerSubmit, amountIsValid } =
    useAddItemToCart(id, title, price, image, amountInputRef);

  return (
    <div
      key={index}
      className="col-span-1 w-full bg-theme-dark-grey rounded-[30px] py-3"
    >
      <div className="flex items-center justify-between gap-x-3 min-w-full min-h-[145px] max-h-[145px] h-full pl-4 pr-2 py-2">
        <div className="flex-1 flex flex-col h-full justify-between">
          <Link href={`/food/${id}`}>
            <h2
              data-testid="food-title"
              className="capitalize text-lg mb-1 font-medium"
            >
              {title}
            </h2>
            <div className="flex flex-row flex-wrap">
              {ingredients.length > 7
                ? ingredients.slice(0, 7).map((el, i) => (
                    <p
                      key={i}
                      className="text-theme-dark-grey2 text-sm font-medium leading-2"
                    >
                      {el}
                    </p>
                  ))
                : ingredients.map((el, i) => (
                    <p
                      key={i}
                      className="text-theme-dark-grey2 text-sm font-medium leading-2"
                    >
                      {el}
                    </p>
                  ))}
            </div>
          </Link>
          <div className="mt-2 flex flex-row justify-between items-center">
            <p className="font-bold text-3xl leading-none">{`$${price}`}</p>
            <FoodForm
              onSubmit={(e: FormEvent) => handlerSubmit(e)}
              ref={amountInputRef}
            />
          </div>
          {!amountIsValid && (
            <p className="mt-4 text-left text-xs font-medium text-theme-dark-orange">
              Please enter a amount (1-5).
            </p>
          )}
        </div>
        <Image
          src={image as string}
          width={115}
          height={115}
          alt="product"
          className="object-cover object-center drop-shadow"
        />
      </div>
    </div>
  );
};

export default Food;

FoodForm.tsx组件

import React, { forwardRef } from "react";
import { FiPlus } from "react-icons/fi";

const FoodForm: React.FC<{ onSubmit: any; ref: any }> = forwardRef(
  ({ onSubmit }, ref) => {
    return (
      <form onSubmit={onSubmit} className="flex items-center gap-x-2">
        <input
          type="number"
          className="border-none outline-none text-center text-xs w-14 h-6 px-4 bg-theme-dark-black rounded-full"
          ref={ref}
        />
        <button
          type="submit"
          className="border-none outline-none bg-theme-green rounded-xl text-2xl p-1 font-bold"
        >
          <FiPlus />
        </button>
      </form>
    );
  }
);

export default FoodForm;

修复步骤

1. 修正FoodForm的类型声明

forwardRef的正确类型写法需要指定泛型参数,不能用React.FC包裹,因为forwardRef返回的组件类型和普通FC不同。同时要移除props中的ref属性(ref不属于组件props,是单独传递的)。

修改后的FoodForm.tsx:

import React, { forwardRef, FormEvent } from "react";
import { FiPlus } from "react-icons/fi";

// 定义组件props类型
type FoodFormProps = {
  onSubmit: (e: FormEvent) => void;
};

// 使用forwardRef并指定泛型:第一个是ref的类型,第二个是props类型
const FoodForm = forwardRef<HTMLInputElement, FoodFormProps>(({ onSubmit }, ref) => {
  return (
    <form onSubmit={onSubmit} className="flex items-center gap-x-2">
      <input
        type="number"
        className="border-none outline-none text-center text-xs w-14 h-6 px-4 bg-theme-dark-black rounded-full"
        ref={ref}
      />
      <button
        type="submit"
        className="border-none outline-none bg-theme-green rounded-xl text-2xl p-1 font-bold"
      >
        <FiPlus />
      </button>
    </form>
  );
});

export default FoodForm;

2. 优化Food组件的props类型(可选但推荐)

TypeScript中应该使用小写的原始类型(string、number、boolean、object),而不是大写的构造函数类型(String、Number等),后者是对象类型,不符合常规用法。

修改Food组件的props类型:

const Food: React.FC<{
  id: string; // 可根据id实际类型调整,比如number
  title: string;
  desc: string;
  price: number;
  kit: boolean;
  category: string;
  ingredients: string[];
  image: string;
  index: Key;
}> = ({ id, title, desc, price, kit, category, index, ingredients, image }) => {
  // ... 剩余代码不变
};

说明

  • forwardRef<HTMLInputElement, FoodFormProps>中,第一个泛型参数是ref指向的DOM元素类型(这里是input),第二个是组件接收的props类型。
  • 给onSubmit指定了(e: FormEvent) => void的类型,替代原来的any,获得更好的类型检查。
  • 移除FoodForm props中的ref属性,因为forwardRef会单独处理ref传递,不需要在props中声明。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.02 22:40:57