我正在创建一个名为useUpdate的钩子,在声明类型时遇到问题,代码如下所示

type CallBack<T extends readonly any[]> = (
  ...args: T
) => void | (() => void | undefined);

function useUpdate<T extends readonly any[]>(
  callback: CallBack<T>,
  deps: T
) {
  const didMount = useRef(false);
  const prevDeps = useRef(deps);

  useEffect(() => {
    if (!didMount.current) {
      didMount.current = true;

      return;
    }

    const clean = callback(...prevDeps.current);

    prevDeps.current = deps;

    return () => {
      if (clean) {
        clean();
      }
    };
  }, deps);
}

使用它时,如果回调包含args,则没有问题,但如果没有为回调提供args,则DEP的类型将不正确

const state: boolean = useSomethingElse(); // get changable data from anywere else

// OK, no type error
useUpdate((prevState) => {
 console.log('I want to compare the current state and prevState', prevState, state);
},[state]);


useUpdate(() => {
 console.log('I only care about the current state', state);
},[state]); // Type error occurs on this line, the message is:
//  Argument of type '[boolean]' is not assignable to parameter of type '[]'.
//  Source has 1 element(s) but target allows only 0.ts(2345)

我知道这是因为TypeScript将T设置为回调参数,如果没有提供参数,则为[],但是有没有办法让TypeScript在设置T时使用DEP类型并跳过回调参数的类型?

推荐答案

有两种方法可以解决此问题:

(1) 将deps设为第一个参数,从deps推断T开始

(2) 使用第二个泛型表示callback:

function useUpdate<T extends readonly any[], Cb extends CallBack<T>>(
  callback: Cb,
  deps: T
) {

Typescript相关问答推荐

脉轮ui打字脚本强制执行图标按钮的咏叹调标签-如何关闭

如何在ts中使用函数重载推断参数类型

即使子网是公共的,AWS CDK EventBridge ECS任务也无法分配公共IP地址

如果一个变量不是never类型,我如何创建编译器错误?

如何使用泛型类型访问对象

状态更新后未触发特定元素的Reaction CSS转换

无法正确推断嵌套泛型?

TypeScrip表示该类型不可赋值

被推断为原始类型的交集的扩充类型的交集

已解决:如何使用值类型限制泛型键?

Angular文件上传到Spring Boot失败,多部分边界拒绝

如何在typescript中为this关键字设置上下文

vue-tsc失败,错误引用项目可能无法禁用vue项目上的emit

基元类型按引用传递的解决方法

Select 类型的子项

TypeScript中的这些条件类型映射方法之间有什么区别?

React Context TypeScript错误:属性';firstName';在类型';iCards|iSearch';

将带有额外id属性的Rust struct 展平回TypeScript单个对象,以返回wasm-bindgen函数

如何为字符串模板文字创建类型保护

基于泛型的柯里化函数的条件参数