繁体   English   中英

从包装的 function 推断包装器的类型

[英]Infer the type of a wrapper from wrapped function

目的是从包装的 function 推断包装器的类型,即从参数类型返回类型。

我无法通过infer实现这一点:

function wrap<T extends ((...args: any[]) => any) & { flag?: string }>(wrapped: T extends infer R ? R : never): T {
        let wrapper = function () {
            // ...
            return wrapped(...arguments);
        } as T;

        wrapper.flag = wrapped.flag;

        return wrapper;
}

let wrapped = (a: number, b: number) => `${a}{b}`;

// wrapper is ((...args: any[]) => any) & { flag?: string }
// should be ((a: number, b: number) => string & { flag?: string }
let wrapper = wrap(wrapped);

// foo is any
// should be string
let foo = wrapper('invalid');

在这种情况下如何在不明确指定包装器类型的情况下做到这一点?

给定类型T extends infer R? R: never T extends infer R? R: never ,编译器几乎肯定无法推断出任何对T有用的东西(因为它倾向于推迟评估这种条件类型,直到它为时已晚而无法推断T )。 由于该类型本质上等同于T ,因此我们将在下面使用T

我认为wrap()签名和实现应该是这样的:

function wrap<T extends ((...args: any[]) => any)>(
  wrapped: T & { flag?: string }): T & { flag?: string } {
  let wrapper = function () {
    // ...
    return wrapped(...arguments);
  } as T & { flag?: string };

  wrapper.flag = wrapped.flag;

  return wrapper;
}

也就是说,我们将使用泛型参数T来表示 function 类型,并将{flag?: string}保留为单独的非泛型 object 类型,与T相交。 您需要执行此类操作的原因与可选属性的可分配性规则有关:

在 TypeScript 中,缺少属性的 object 类型被认为可分配给具有任何类型的可选属性的 object。 例如,类型{foo: string}可分配给类型{foo: string, bar?: number} 如果您有一个泛型类型T extends {foo: string, bar?: number} ,则T可能是{foo: string} ,完全缺少bar属性。

在您的情况下,如果您有一个通用类型T extends ((...args: any[])=>any) & {flag?: string} ,并传入一个没有已知flag属性的 function 作为推理站点T ,编译器将推断T只是没有flag属性的 function 类型。 然后 function output 也没有flag属性,你很难过。

为了确保编译器将输入和 function 的 output 解释为具有可选flag属性,我们需要在输入和 Z78E6221F6393D1456681DB398F 中显式包含它,并且不给编译器失去跟踪它的机会, .

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

Playground 代码链接

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM