通过泛型进行类型保护递归



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

我尝试过的:

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);

尽管传递了类型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<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上应用<+运算符,因此,我们需要确保value和lim是兼容的类型。因此,我们需要确保N和T支持这些操作,因此从number扩展而来(您可以使用并集类型添加更多类型)。

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

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

TS游乐场

老实说,对于这个确切的问题,我认为使用泛型是过分的。我宁愿只使用实际类型。像这个

最新更新