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

如何编写具备正确TypeScript属性校验的函数包装器自定义Hook

如何编写具备正确TypeScript属性校验的函数包装器自定义Hook

这个场景太常见了——重复获取level这类公共参数确实会让代码冗余又难维护,你已经找对了方向:用自定义Hook封装公共逻辑,把level自动注入到目标函数里。不过当前的类型问题是因为泛型没有正确处理多个函数的独立类型,导致所有函数的参数被合并到一起了,咱们来一步步修复它。

问题根源分析

你之前的Hook用了T extends any[]作为泛型,这会让TypeScript把传入的多个函数参数当成一个联合类型数组,而不是每个元素独立的元组。所以最终生成的包装函数类型会是所有原函数参数的合并,也就出现了returnFn2要求age、returnFn3要求username的错误。

修复后的自定义Hook

我们需要用元组泛型结合映射类型,让每个传入的函数对应一个独立的包装函数类型,确保每个包装函数只校验自己需要的参数(自动排除level):

import { useGetUserInfo } from './your-path-to-useGetUserInfo'; // 替换成你的实际路径

// 定义泛型:接受一个函数元组,每个函数都接收一个包含level的对象参数
const useWrapperFn = <Fns extends readonly ((props: { level: any; [key: string]: any }) => void)[]>(
  ...fns: Fns
) => {
  const { level } = useGetUserInfo();

  // 对元组中的每个函数单独处理,生成对应的包装函数
  return fns.map((fn) => {
    return (props: Omit<Parameters<typeof fn>[0], 'level'>) => {
      fn({ ...props, level });
    };
  }) as {
    [K in keyof Fns]: Fns[K] extends (props: infer P) => void
      ? (props: Omit<P, 'level'>) => void
      : never;
  };
};

export default useWrapperFn;

关键类型逻辑解释

  1. 元组泛型约束:Fns extends readonly ((props: { level: any; [key: string]: any }) => void)[] 确保传入的每个函数都接收一个包含level的对象参数,符合你的业务场景。
  2. 映射类型生成返回值:{ [K in keyof Fns]: ... } 遍历元组的每个索引,为每个位置的函数单独生成包装类型:
    • 用infer P提取原函数的参数类型P
    • 用Omit<P, 'level'>去掉level字段,作为包装函数的参数要求
  3. 类型断言对齐:把map返回的数组断言成我们定义的映射类型,让TypeScript正确识别每个包装函数的独立类型。

验证正确用法

现在你的组件里调用时,每个包装函数都会有精准的类型校验:

// Component1
const Component1 = () => {
  const [returnFn1] = useWrapperFn(fn1);
  useEffect(() => {
    returnFn1({ type: 1 }); // ✅ 正常通过校验
    // returnFn1(); ❌ TS报错:缺少必填属性type
  }, []);
};

// Component2
const Component2 = () => {
  const [returnFn2, returnFn3] = useWrapperFn(fn2, fn3);
  useEffect(() => {
    returnFn2({ username: 'username' }); // ✅ 正常通过校验,不会要求age
    // returnFn2({}); ❌ TS报错:缺少必填属性username
  }, []);
  useEffect(() => {
    returnFn3({ age: '27' }); // ✅ 正常通过校验,不会要求username
    // returnFn3({}); ❌ TS报错:缺少必填属性age
  }, []);
};

这样不仅JavaScript逻辑保持正确,TypeScript的类型校验也能精准对应每个函数的参数要求,完美解决你的问题!

备注:内容来源于stack exchange,提问作者Jake Lam

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.23 11:29:09