簡體   English   中英

如何在 TypeScript 中實現類型化的“兩者”function?

[英]How can I implement a typed “both” function in TypeScript?

故事書操作插件提供了一種記錄回調調用的便捷方式:

renderButton({onClick: action('onClick')});

action調用返回一個 function 記錄字符串 ( onClick ) 和調用它的 arguments 。

有時我想同時擁有action和其他東西:

renderButton({
  onClick: (arg1, arg2, arg3) => {
    action('onClick')(arg1, arg2, arg3);
    // ... my code
  }
});

由於我必須傳入所有 arguments,因此action調用變得更加冗長。 所以我實現了一個both讓我寫:

renderButton({
  onClick: both(action('onClick'), (arg1, arg2, arg3) => {
    // ... my code
  })
});

這很好用,直到我嘗試添加 TypeScript 類型。 這是我的實現:

function both<T extends unknown[], This extends unknown>(
  a: (this: This, ...args: T) => void,
  b: (this: This, ...args: T) => void,
): (this: This, ...args: T) => void {
  return function(this: This, ...args: T) {
    a.apply(this, args);
    b.apply(this, args);
  };
}

此類型在運行時檢查並工作,但根據上下文,它會導致不需要的any類型或類型錯誤。 例如:

const fnWithCallback = (cb: (a: string, b: number) => void) => {};

fnWithCallback((a, b) => {
  a;  // type is string
  b;  // type is number
});

fnWithCallback(
  both(action('callback'), (a, b) => {
    a;  // type is any
    b;  // type is any
  }),
);

fnWithCallback(
  both(action('callback'), (a, b) => {
//                         ~~~~~~~~~~~
// Argument of type '(a: T[0], b: T[1]) => number' is not assignable to
// parameter of type '() => void'.
  }),
);

是否可以both從回調上下文中正確捕獲參數類型? 為了避免可能來自action聲明any類型:

export type HandlerFunction = (...args: any[]) => void;

這是帶有完整示例的游樂場鏈接

這應該有效並保持正確的回調參數類型:

type UniversalCallback<Args extends any[]> = (...args: Args) => void;
function both<
    Args extends any[],
    CB1 extends UniversalCallback<Args>,
    CB2 extends UniversalCallback<Args>
>(fn1: CB1, fn2: CB2): UniversalCallback<Args> {
  return (...args:Args) => {
    fn1(...args);
    fn2(...args);
  };
}

該解決方案忽略了this ,但我不知道這對您來說是否有問題,因為您提供的使用示例並沒有真正使用this

擴展支持以將this傳遞給回調很容易:

type UniversalCallback<T, Args extends any[]> = (this:T, ...args: Args) => void;
function both<
    T,
    Args extends any[],
    CB1 extends UniversalCallback<T, Args>,
    CB2 extends UniversalCallback<T, Args>
>(fn1: CB1, fn2: CB2): UniversalCallback<T, Args> {
  return function(this:T, ...args:Args) {
    fn1.apply(this, args);
    fn2.apply(this, args);
  };
}

它在以下測試中完美運行:

class A { f() {} }

const fnWithCallback = (cb: (this: A, a: string, b: number) => void) => { };

fnWithCallback(function(a, b) {
  a;  // type is string
  b;  // type is number
  this.f(); // works
});

fnWithCallback(
  both(function (a) {
    a; // correct type
    this.f(); // works
  }, function (a, b) {
    a; b; // correct types
    this.f(); // works
  }),
);

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM