NextJS+TypeScript项目中使用forwardRef遇类型错误求解决
修复NextJS+TypeScript中forwardRef的类型错误
我在NextJS+TypeScript项目中拥有一个添加商品到购物车的表单,该表单是独立组件,使用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
相关产品推荐
相关产品推荐

