TypeScript接口中如何定义React组件的函数类型props
React + TypeScript 回调Prop类型定义与react-hook-form重置实现
你之前定义onSaveExpenseData:()=>void不生效的核心原因是:这个类型声明代表该函数不需要接收任何参数,但实际业务中你需要在ExpenseForm提交表单时,把收集到的表单数据作为参数传入这个回调,参数类型不匹配就会导致TS报错。
以下是完整的实现方案:
1. 抽离公共类型
把多个组件复用的数据类型统一抽离,避免重复定义:
// 可以单独存为types.ts,三个组件共同引入 export interface ExpenseFormInput { enteredTitle: string; enteredAmount: number; enteredDate: string; } // 最终生成的费用项,在表单数据基础上增加id字段 export interface ExpenseItem extends ExpenseFormInput { id: string; }
2. 修复ExpenseForm组件类型与表单重置逻辑
// ExpenseForm.tsx import { useState } from 'react'; import { useForm } from 'react-hook-form'; import type { ExpenseFormInput } from './types'; // 定义组件接收的Props类型 interface ExpenseFormProps { // 明确回调函数需要接收ExpenseFormInput类型的参数,无返回值 onSaveExpenseData: (formData: ExpenseFormInput) => void; } const ExpenseForm = (props: ExpenseFormProps) => { const [userInput, setUserInput] = useState<ExpenseFormInput>({ enteredTitle: "", enteredAmount: 10, enteredDate: "", }); const { register, handleSubmit, reset } = useForm<ExpenseFormInput>({ // 配置表单默认值,重置时会回到该状态 defaultValues: { enteredTitle: "", enteredAmount: 10, enteredDate: "" } }); const onValid = (data: ExpenseFormInput) => { setUserInput(data); // 调用父组件传入的回调,传递表单数据 props.onSaveExpenseData(data); // 无需逐个调用resetField,直接调用reset一次性重置所有字段 reset(); }; return ( <form onSubmit={handleSubmit(onValid)}> <div> <label>费用名称</label> <input {...register("enteredTitle", { required: true })} /> </div> <div> <label>金额</label> <input type="number" {...register("enteredAmount", { required: true, min: 0.01 })} /> </div> <div> <label>日期</label> <input type="date" {...register("enteredDate", { required: true })} /> </div> <button type="submit">添加费用</button> </form> ); }; export default ExpenseForm;
3. 修复NewExpense组件类型
// NewExpense.tsx import ExpenseForm from './ExpenseForm'; import type { ExpenseFormInput, ExpenseItem } from './types'; interface NewExpenseProps { onAddExpense: (expense: ExpenseItem) => void; } const NewExpense = (props: NewExpenseProps) => { const saveExpenseDataHandler = (enteredExpenseData: ExpenseFormInput) => { const expenseData: ExpenseItem = { ...enteredExpenseData, id: Math.random().toString(), }; console.log(expenseData); props.onAddExpense(expenseData); }; return ( <div className="new-expense"> <ExpenseForm onSaveExpenseData={saveExpenseDataHandler} /> </div> ); }; export default NewExpense;
4. 修复App组件类型
//App.tsx import NewExpense from './NewExpense'; import type { ExpenseItem } from './types'; const App = () => { const expenses: ExpenseItem[] = [ { id: "xxxx", enteredTitle: "xxx", enteredAmount: 100, enteredDate: "2022-06-16", }, ]; const addExpenseHandler = (expense: ExpenseItem) => { console.log(expense); // 此处可更新expenses数组渲染列表 }; return ( <div> <NewExpense onAddExpense={addExpenseHandler} /> </div> ); }; export default App;
关键说明
- 函数类型定义必须和实际调用时的参数、返回值完全匹配,给回调传参就必须在类型里声明对应的参数类型。
- react-hook-form的
reset()方法比逐个调用resetField更适合全表单重置场景,配合defaultValues配置可以精准控制重置后的初始状态。 - 跨组件复用的类型建议抽离到独立文件维护,避免重复定义产生的类型冲突。
内容的提问来源于stack exchange,提问作者hse
相关产品推荐
相关产品推荐

