【问题标题】:Typesafing Recursion Through Generics?通过泛型对递归进行类型保护?
【发布时间】:2021-05-03 21:34:52
【问题描述】:

我正在尝试找到一种使用泛型对递归(最后返回一个数字)进行类型安全的方法。

我尝试了什么:

function recursion<N,T>(value:N, lim:N):T|N {
        if(value < lim) return recursion<N, T>(value+1,lim);

        return value;
}

recursion<number, Function>(0,10);

尽管传递了 type number,Typescript 还是决定给我一个错误:

TSError: ⨯ Unable to compile TypeScript:
src/main.ts:2:41 - error TS2365: Operator '+' cannot be applied to types 'N' and 'number'.

2  if(value < lim) return recursion<N, T>(value+1,lim);

我认为只要我在泛型上传递了number 类型,就可以进行操作,但似乎并非如此。为什么会这样?是否有任何可能的解决方法?

尝试过(不起作用):

return recursion<number, Function>(value+1,lim)

日志:

src/main.ts:2:53 - error TS2365: Operator '+' cannot be applied to types 'N' and 'number'.

2  if(value < lim) return recursion<number, Function>(value+1,lim);
                                                      ~~~~~~~
src/main.ts:2:61 - error TS2345: Argument of type 'N' is not assignable to parameter of type 'number'.

2  if(value < lim) return recursion<number, Function>(value+1,lim);

【问题讨论】:

  • 你需要 function recursion&lt;N extends number&gt;(value: N, lim: N): N 告诉 TypeScript N 永远是一个数字。该函数在其定义处进行类型检查,而不是在每个调用站点 - 它不是模板而是通用的。你的第二个类型参数T 也是没用的。

标签: typescript recursion functional-programming typescript-generics union-types


【解决方案1】:
function recursion<N, T>(value:N, lim:N): T | N {
 if(value < lim) return recursion<N, T>(value+1,lim);
 return value;
}

为什么会这样?

recursion 采用两个泛型,可能有也可能没有定义+ 运算符。看到此签名,您似乎可以将value 作为参数的任何内容(如对象)传递。如果 Typescript 允许这样做,它不会导致预期的行为。

此外,您知道在您的情况下,您(最终)返回值的类型。所以,T 是我们已知的,它的类型是 N,因为这就是递归的终止条件。

如何解决?

// 1. Make sure value has compatible type
function recursion<N extends number>(value: N, lim: N): N {
  if (value < lim) {
    // 2. Downcast to N
    return recursion((value + 1) as N, lim);
  }

  return value;
}
  1. 我们需要确保运算符适用于类型。我们在 valuelim 上应用 &lt;+ 运算符,因此,我们需要确保 value 和 lim 是兼容的类型。因此,我们需要确保 N 和 T 支持这些操作,因此,扩展自 number(您可以使用 union 类型添加更多类型)。

  2. + 运算符返回一个数字,该数字可能与 N 不兼容。因此,我们需要将其显式转换为 N 以兼容递归调用。

  3. 我们还应该明确告诉返回类型,函数最终返回,所以返回是N 而不是函数。

TS Playground

老实说,对于这个确切的问题,我认为使用泛型是一种矫枉过正。我宁愿只坚持实际的类型。 Like this

【讨论】:

  • 知道了!非常感谢,我什至没有意识到它可以通过常规方式实现。我这样做是在假设我不能返回一个递归而不将它作为一个函数进行类型化。
猜你喜欢
  • 2017-12-23
  • 1970-01-01
  • 2020-06-15
  • 2020-06-27
  • 2021-06-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-09-06
相关资源
最近更新 更多