我正试图找到一种使用泛型对递归(在末尾返回一个数字)进行类型安全的方法。
我尝试过的:
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;
}
我们需要确保运算符在类型上工作。我们在
value
和lim
上应用<
和+
运算符,因此,我们需要确保value和lim是兼容的类型。因此,我们需要确保N和T支持这些操作,因此从number
扩展而来(您可以使用并集类型添加更多类型)。+
运算符返回一个数字,该数字可能与N
不兼容。因此,我们需要显式地将其强制转换为N,以便与递归调用兼容。我们还应该明确地告诉返回类型,函数最终返回,所以返回是
N
,而不是函数。
TS游乐场
老实说,对于这个确切的问题,我认为使用泛型是过分的。我宁愿只使用实际类型。像这个