【问题标题】:Enforce function signature within an object在对象中强制执行函数签名
【发布时间】:2021-09-12 01:24:12
【问题描述】:

我正在寻找一种方法来定义具有两个函数的对象,其中一个函数总是将另一个函数的返回类型作为参数。例如

type DoActionArgType = { contactId: string };

type Args<T> = 
{
  doAction: (arg: DoActionArgType) => string; // <-- returns string
  onEnd?: (arg: string) => void; // <-- takes string as the argument
}

现在我希望它适用于任意返回类型和承诺,这很好,除非我不将类型添加到函数 doAction 函数参数中。

export type $Unwrap<T> = T extends Promise<infer U>
    ? U
    : T extends (...args: any) => Promise<infer U>
    ? U
    : T extends (...args: any) => infer U
    ? U
    : T;

type DoActionArgType = { contactId: string };

type Args<T> = 
{
  doAction: (arg: DoActionArgType) => Promise<T>;
  onEnd?: (arg: $Unwrap<T>) => void;
}

function test<T>(arg: Args<T>) {}

const doAction = async ({ contactId }) => 1

test({
  // doAction: async ({ contactId }: DoActionArgType) => 1, // Works
  // doAction: async () => 1, // Works
  // doAction, // Works
  doAction: async ({ contactId }) => 1, // <--- Does not work
  onEnd: (arg) => {
    const a:number = arg
  }
})

我假设打字稿不理解函数签名匹配?因为contactId 实际上输入了string,只是onEnd 的arg 输入了unknown。有没有办法在不将DoActionArgType 类型添加到doAction 函数的情况下完成这项工作?

Typescript Playground

【问题讨论】:

  • 你需要$Unwrap类型做什么,为什么不直接使用onEnd?: (arg: T) =&gt; void
  • @MrCodingB (arg: T) =&gt; void 不起作用

标签: typescript


【解决方案1】:

你需要做一个帽子戏法:

type DoActionArgType = { contactId: string };

type PromiseUnwrap<P> =
  P extends Promise<infer Value>
  ? Value
  : P

const test = <T,>(arg: {
  doAction: (a_arg: DoActionArgType) => T;
  onEnd: <U extends T>(b_arg: PromiseUnwrap<U>) => void;
}) => {
  // ...
};

test({
  doAction: async ({ contactId }) => 1,
  onEnd: (arg) => {
    arg // number
    arg.toExponential // ok
  }
})

Playground

PromiseUnwrap - 获得 Promise 返回类型。

你可能会问,为什么这个功能不起作用:

const test = <T,>(
  arg: {
    doAction: (a_arg: number) => T;
    onEnd: (b_arg: T) => void
  }) => {
  // ...
};

Here你可以找到一个很好的答案。

如果你想了解更多关于 typescript 中的回调,你可以阅读我的article。第一个例子是你的

【讨论】:

  • 我认为在这种情况下您应该保留 OP 的原始 $Unwrap 类型,因为现在您假设 T 必须是 Promise,但没有指定
  • 随意使用您的 $Unwrap 版本。在这种情况下,它以相同的方式工作
  • @MrCodingB 已更改
  • 你为什么用&lt;T,&gt;而不是&lt;T&gt;?这有什么区别吗?
  • @Philiiiiiipp 是关于 JSX 解析的。例如,它在 IDE 中不带逗号即可工作,但是当您想在操场上使用 &lt;T&gt; 时 - 它会给出错误,因为 TS 需要 jsx。因为我一直在使用 TS Playground,所以我必须在任何地方都放一个逗号
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2012-10-20
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多