如何为useModel Hook根据方法类型正确定义第三个参数类型
解决useModel Hook中参数类型随方法动态匹配的问题
要让useModel的第三个参数能根据传入的method自动匹配对应方法的参数类型,我们可以通过类型映射和条件类型实现类型约束,同时修正Hook内部的调用逻辑,以下是具体方案:
1. 定义方法与参数类型的映射关系
先为BaseApiModel的静态方法创建参数类型映射,把每个方法的参数转换成调用useModel时传入的options结构:
// 定义各方法对应的options类型 type ModelMethodOptions<T extends typeof BaseApiModel> = { get: { id?: number; params?: QueryFilterParams }; post: { data: Omit<InstanceType<T>, "id"> }; // 按需补充put/patch/delete等其他方法的参数类型 }; // 提取所有支持的方法名 type Methods = keyof ModelMethodOptions<any>;
这里InstanceType<T>用来获取模型类(比如Art)的实例类型,Omit<InstanceType<T>, "id">正好对应post方法需要的参数类型。
2. 修改useModel的类型定义与逻辑
调整useModel的泛型和参数类型,让options的类型随method动态变化,同时修正函数调用逻辑(避免方法被立即执行):
function useModel<T extends typeof BaseApiModel, M extends Methods>( model: T, method: M, options?: ModelMethodOptions<T>[M] ) { // 处理get方法的查询逻辑 if (method === "get") { const { id, params } = options || {}; return useQuery({ queryKey: [model.key, method, id, params], queryFn: () => model.get(id, params), enabled: true, }); } // 处理post等mutation方法的逻辑 const mutationFn = async () => { switch (method) { case "post": return model.post((options as ModelMethodOptions<T>["post"]).data); // 按需补充put/patch/delete等方法的处理逻辑 default: throw new Error(`Unsupported method: ${method}`); } }; return useMutation({ mutationKey: [model.key, method, options], mutationFn, }); }
3. 关键优化点说明
- 动态类型匹配:通过
ModelMethodOptions<T>[M],当传入不同method时,options会自动匹配对应类型——比如传入"get"时只能传{ id?: number; params?: QueryFilterParams },传入"post"时只能传{ data: Omit<Art, "id"> }。 - 修正函数调用:之前直接写
queryFn: model[method](options)会立即执行方法,改成() => model.get(id, params)才符合useQuery的要求(queryFn需要是返回Promise的函数)。 - 类型安全校验:通过类型约束,编辑器会自动提示参数错误,比如给post方法传带id的data时会直接报错。
测试调用示例
现在调用useModel时,类型系统会自动做校验:
// 正确:get方法接受id和params参数 useModel(Art, "get", { id: 7 }); // 正确:post方法的data符合Omit<Art, "id">类型 useModel(Art, "post", { data: { title: "Art title", description: "test" } }); // 错误:post方法的data不能包含id,编辑器会直接报错 useModel(Art, "post", { data: { id: 1, title: "Art title" } });
内容的提问来源于stack exchange,提问作者atricoky
相关产品推荐
相关产品推荐

