【问题标题】:How to explicitly type a generic function in TypeScript?如何在 TypeScript 中显式键入泛型函数?
【发布时间】:2020-12-03 03:12:32
【问题描述】:

问题

我有以下通用函数类型:

type Validator<TInput, TOutput extends TInput> = (value: TInput) => Validated<TOutput>;

现在我想实现这个类型,所以我做了以下操作:

const isNotNull: Validator<T | null, T> = <T>(value: T | null): Validated<T> => {
    // Implementation here
};

这不起作用,因为在定义之前使用了T

我知道我可以推断出 isNotNull 的类型,但我想明确将其声明为 Validator 作为约束。我该怎么做?


上下文

Validator 类型将用作函数参数,如下所示:

function validate<TInput, TOutput>(
    value: TInput,
    validator: Validator<TInput, TOutput>
): TOutput {}

当然实际上不需要这个功能。实际情况更复杂,但我已将其精简到最低限度。

这就是为什么Validator 必须是通用的。

【问题讨论】:

    标签: typescript generics typescript-generics


    【解决方案1】:

    TypeScript 缺乏将isNotNull 函数描述为Validator 类型所必需的表达能力。如果 TypeScript 具有如 microsoft/TypeScript#17574 中所述的任意“通用值”,则可能会这样说:

    declare const isNotNull: forall T, Validator<T | null, T>; // not valid TS, error
    

    但目前没有办法做到这一点。 (有关更多信息,我会在 this question 的回答中继续介绍 TypeScript 中的泛型。)

    如果无法以编程方式执行此操作,您可能需要手动执行此操作:

    declare const isNotNull: <T>(value: T | null) => Validated<T>;
    

    幸运的是,虽然编译器无法表达 isNotNullValidator 相关,但它可以识别它。所以你仍然可以毫无问题地将isNotNull 传递给validate()

    validate(Math.random() < 0.5 ? 123 : null, isNotNull);
    // function validate<number | null, number>(
    //   value: number | null, validator: Validator<number | null, number>
    // ): number
    

    编译器发现isNotNull 可以被视为Validator&lt;number | null, number&gt;


    我能想到的唯一其他方法是表示一个泛型函数,当您使用T 类型参数调用它时返回 Validator&lt;T | null, T&gt;,如下所示:

    const getIsNotNull = <T>(): Validator<T | null, T> => isNotNull;
    validate(Math.random() < 0.5 ? "hey" : null, getIsNotNull<"hey">());
    

    这使您能够说“isNotNullValidator 有关”,但代价是无用的无参数柯里化函数。我更喜欢直接使用validateisNotNull


    Playground link to code

    【讨论】:

      猜你喜欢
      • 2021-11-17
      • 2020-02-27
      • 2021-06-15
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多