这是可能的,但是我不会在 PROD 代码上过多依赖此逻辑:
type MAXIMUM_ALLOWED_BOUNDARY = 999
type ComputeRange<
N extends number,
Result extends Array<unknown> = [],
> =
(Result['length'] extends N
? Result
: ComputeRange<N, [...Result, Result['length']]>
)
type Add<A extends number, B extends number> = [...ComputeRange<A>, ...ComputeRange<B>]['length']
type IsGreater<A extends number, B extends number> = IsLiteralNumber<[...ComputeRange<B>][Last<[...ComputeRange<A>]>]> extends true ? false : true
type Last<T extends any[]> = T extends [...infer _, infer Last] ? Last extends number ? Last : never : never
type RemoveLast<T extends any[]> = T extends [...infer Rest, infer _] ? Rest : never
type IsLiteralNumber<N> = N extends number ? number extends N ? false : true : false
type AddIteration<Min extends number, Max extends number, ScaleBy extends number, Result extends Array<unknown> = [Min]> =
IsGreater<Last<Result>, Max> extends true
? RemoveLast<Result>
: AddIteration<
Min, Max, ScaleBy, [...Result, Add<Last<Result>, ScaleBy>]
>
// [5, 13, 21, 29, 37]
type Result = AddIteration<5, 40, 8>
操场 https://tsplay.dev/w6L7Gm
请看我的answer https://stackoverflow.com/questions/69089549/typescript-template-literal-type-how-to-infer-numeric-type#answer-69090186 and article https://catchts.com/range-numbers
解释ComputeRange
你可以找到this https://stackoverflow.com/questions/69089549/typescript-template-literal-type-how-to-infer-numeric-type#answer-69090186回答和我的文章 https://catchts.com/range-numbers
Add
- 只是连接两个数组并返回新的长度。就像 :
const add=(xl:number[], yl:number[]) => [...xl,...yl].length
IsLiteralNumbe
- 检查提供的数字是否是字面数字,例如2
or 42
或者只是一般类型number
.
Last
返回数组的最后一个元素
IsGreater
检查最后一个元素是否ComputeRange<A>
可以用作索引ComputeRangeB
。请记住,中的所有元素ComputedRange
也是索引。
AddIteration
- 是一种递归实用程序类型,它检查 Result 的最后一个元素是否大于 Max。如果是 - 返回没有最后一个元素的结果,否则,通过加法递归调用自身。
在这里你可以测试js表示。我尽可能地接近,但并不是所有的事情都能表达出来。
const add = (a: number, b: number) => [...computeRange(a), ...computeRange(b)]['length']
const isLiteralNumber = (value: any) => typeof value === 'number'
const last = (xl: number[]) => {
//const [...rest, last] = xl
return xl[xl.length - 1]
}
const computeRange = (n: number) => Array(n).fill(0).map((_, index) => index)
const isGreater = (a: number, b: number) => isLiteralNumber([...computeRange(b)][last(computeRange(a))]) ? false : true
const addIteration = (min: number, max: number, scaleBy: number, result = [min]): number[] => {
if (isGreater(last(result), max)) {
return result
}
return addIteration(min, max, scaleBy, [...result, add(last(result), scaleBy)])
}
const result = addIteration(5, 40, 8)
// [ 5, 13, 21, 29, 37, 45 ]
console.log({ result })