【问题标题】:Generic types for function which creates functions that wrap other functions创建包装其他函数的函数的函数的泛型类型
【发布时间】:2019-10-04 09:34:46
【问题描述】:

如何为函数createWrapper 编写泛型类型,以使示例末尾的返回类型与指定的一样?

function createWrapper(wrapper) {
  return fn => wrapper(fn);
}

const wrap = createWrapper(fn => {
  if (Math.random() < 0.5) {
    return 4 as const;
  }
  const result = fn();
  return result === 0 ? null : result;
});

const nullOrOneOrFour = wrap(() => {
  return Math.random() < 0.5 ? (0 as const) : (1 as const);
});

const twoOrThreeOrFour = wrap(() => {
  return Math.random() < 0.5 ? (2 as const) : (3 as const);
});

// ReturnType<typeof nullOrOneOrFour> -> null | 1 | 4
// ReturnType<typeof nullOrTwoOrThreeOrFour> -> null | 2 | 3 | 4

函数createWrapper 的定义是唯一需要显式类型注释的区域。理想情况下,其他一切都可以推断出来。


在玩了更多之后,我想我可能需要像高阶类型这样的东西才能正确地做到这一点(即泛型泛型)。这条评论似乎与我想要完成的事情有关:https://github.com/microsoft/TypeScript/issues/1213#issuecomment-523245130

【问题讨论】:

  • 抱歉,createWrapper 的代码是什么。这不是你想要输入的内容
  • @jstuartmilne 我添加了createWrapper的代码
  • 在评论中你提到了nullOrTwoOrThreeOrFour,但在代码中你有twoOrThreeOrFour。评论应该是twoOrThreeOrFour吗?

标签: typescript


【解决方案1】:

我已经完成并为所有内容添加了类型,直到可以推断出其余部分。 您可能可以选择不同的东西来添加类型以正确推断结果。

输入的代码

function createWrapper<Output, FinalOutput>(wrapper: (fn: () => Output) => FinalOutput): (fn: () => Output) => FinalOutput {
    return fn => wrapper(fn);
}

const wrap: <Output>(fn: () => Output) => Output | 4 | (0 extends Output ? null : never) = createWrapper(fn => {
    if (Math.random() < 0.5) {
        return 4 as const;
    }
    const result = fn();
    return (result as unknown === 0 ? null : result) as any;
});

const nullOrOneOrFour = wrap(() => {
    return Math.random() < 0.5 ? (0 as const) : (1 as const);
});

const twoOrThreeOrFour = wrap(() => {
    return Math.random() < 0.5 ? (2 as const) : (3 as const);
});

nullOrOneOrFour 被推断为null | 1 | 4, 和 twoOrThreeOrFour 被推断为2 | 3 | 4

createWrapper

接受一个函数,该函数接受一个函数并返回一些值, 并返回一个函数,该函数接受一个函数并返回该值。

老实说,我不太确定它的用途,因为它对接受一个参数的函数没有任何作用。也许你有一些我想不出的用例,但无论哪种方式,它都是打字系统的一个很好的例子。

wrap

获取一个输出某些东西的函数,然后输出那个东西,4,或者null,如果那个东西是0

不幸的是,我不得不在此函数中将as unknown 添加到result,因为显然您无法将任意类型与打字稿中的0 进行比较。我不认为这是有道理的,但它是intended behaviour

另外,我必须将as any 添加到最终返回值中,因为我无法输入它,因此只有在0 extends Output 时才能使用null。它使这个函数的类型变得丑陋,但使它的任何调用者的类型推断都很好。如果另一个答案可以摆脱as any,但仍然可以对最后两个常量进行正确的类型推断,那么他们的答案可能比我的要好。

【讨论】:

  • 我在问题中添加了一些额外的上下文以使问题更清晰。 createWrapper 是唯一应该具有显式类型注释的函数。
  • @Braden 这可能有点乐观。无法正确推断以下函数的返回类型:function replaceNullWithZero&lt;T&gt;(t: T) { return t === 0 ? null : t; } 因为您在 wrap 中有类似的内容,所以无论您使用 createWrapper 做什么,它都不会正确推断类型。
【解决方案2】:

这是函数返回类型的简单示例。

greet() : number {
    return n;
}

【讨论】:

  • 甚至没有接近所问问题的复杂性
猜你喜欢
  • 1970-01-01
  • 2018-02-23
  • 2021-10-06
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-12-14
  • 1970-01-01
相关资源
最近更新 更多