Typescript-嵌套箭头功能键入

问题描述 投票:0回答:1

我有用于延迟执行功能的代码

export type DeferredFunction<T> = () => T | PromiseLike<T>;

export class Deferrable<T> {
  protected df: DeferredFunction<T>;

  constructor(df: DeferredFunction<T>) {
    this.df = df;
  }

  public async execute(): Promise<T> {
    return this.df();
  }
}

export const defer = <T>(df: DeferredFunction<T>): Deferrable<T> => new Deferrable<T>(df);

效果很好,我可以运行类似的代码

await defer(() => someFunction('foo', 'bar')).execute();

但是我要执行的操作是键入DeferredFunction,这样我可以指定内部函数的签名,但无法使其正常工作。在一般情况下,上述方法有效,但是当我想限制参数以使其特定于某种类型的函数时,我就没有这种控制权。

为清楚起见,我希望能够键入内部函数的输入,例如(作为示例)

export type InnerDeferredFunction<T> = (a: string, b: number, c: SomeObjectType) => T | PromiseLike<T>

任何帮助将不胜感激!

node.js typescript arrow-functions
1个回答
0
投票

您在说什么“内部功能”?是someFunction吗?如果是这样,则DeferredFunction<T>的类型没有句柄,因为它是DeferredFunction<T>implementation调用的函数。 TypeScript中无法指定“其实现必须调用(x: string, y: number, z: boolean) => string类型的函数的函数”。实现细节不是函数的调用签名的一部分。


我可以想象开始解决此问题的唯一方法是DeferredFunction<T>接受要调用的内部函数作为参数,并接受要使用的参数列表。这可能不是您要查找的内容,但这是类型系统可以表示的最接近的内容。

类似这样的东西:

export type InnerDeferredFunction<T, A extends any[]> = (...args: A) => T | PromiseLike<T>;
export type ZeroArgDeferredFunction<T> = InnerDeferredFunction<T, []>

这里我保持A通用,但您可以将其指定为一些硬编码的参数列表。我已将您的DeferredFunction重命名为ZeroArgDeferredFunction,以明确表明它不需要参数。

但是现在Deferrable需要了解T A

export class Deferrable<T, A extends any[]> {
  protected df: ZeroArgDeferredFunction<T>;

  constructor(df: InnerDeferredFunction<T, A>, ...args: A) {
    this.df = () => df(...args);
  }

  public async execute(): Promise<T> {
    return this.df();
  }
}

并且您会看到必须通过向其传递内部函数及其参数来构造一个,而ZeroArgDeferredFunction是在构造函数内部构建的,并且没有传递。

定义defer()有多种方法。它可能是您new Deferrable周围的薄包装,或者您可以想象将其拆分为使args首先出现:

export const defer = <A extends any[]>(...args: A) => <T>(
  df: InnerDeferredFunction<T, A>): Deferrable<T, A> => new Deferrable<T, A>(df, ...args);

然后您可以像这样测试它:

function someFunction(x: string, y: string) {
  return (x + y).length;
}
function anotherFunction(x: number, y: number) {
  return (x * y).toFixed()
}

const deferFooBar = defer('foo', 'bar');
await deferFooBar(someFunction).execute(); // okay
await deferFooBar(anotherFunction); // error! string is not assignable to number

一旦调用deferFooBar('foo', 'bar'),返回的值将仅接受可以使用参数foo'bar'安全调用的函数。这意味着someFunction将被接受,anotherFunction将被拒绝。


好的,希望能有所帮助;祝你好运!

Playground link to code

© www.soinside.com 2019 - 2024. All rights reserved.