3

I have a function that is defined as so:

function getRangeBounds(start: number, stop?: number, step?: number) {
  if (step === undefined) step = 1;
  const actualStart = start !== undefined && stop !== undefined ? start : 0;
  const actualStop = stop === undefined ? start : stop;
  return [actualStart, actualStop, step];
}

I want this function's arguments to be typed and be reusable. So I did:

type Range = Parameters<typeof getRangeBounds>;

I want the type Range to be reusable across a couple more functions, namely range and mapRange that will have the following signatures respectively:

export function range(...args: Range): ReadonlyArray<number> {
  /* this will call getRangeBounds at some point */
}

export function mapRange(...rangeArgs: Range, mapper: MapFunc<number> = IdentityMapper) {
  return range(rangeArgs).map(mapper); /* code does not compile */
}

How can I make these functions behave in a way the contract Range is honored by them all and also be possible to use extra args in some functions like the mapRange above?

Edit: I fixed the compilation error above, so mapRange looks like this now:

export function mapRange(rangeArgs: Range, mapper: MapFunc<number>) {
  return range(...rangeArgs).map(mapper);
}

But I now need to call the function like this:

mapRange([start, stop, step])
1
  • 1
    Not sure exactly what you mean. range(...args: Range) is a good solution, you could also destruture the parameters in the argument list if you want: range(...[start, stop, step]: Range) Commented Jul 6, 2020 at 8:24

1 Answer 1

2

Some options to add extra parameters to Range for other functions:

Option 1: Change rest parameter to be the last element
function mapRangeRest(mapper: MapFunc<number>, ...rangeArgs: Range) { ... }

mapRangeRest(mapFunc, 1)
mapRangeRest(mapFunc, 1, 2)
Option 2: Currying
function mapRangeCurry(...rangeArgs: Range_): (mapper: MapFunc<number>) { ... }

mapRangeCurry(1)(mapFunc)
mapRangeCurry(1, 2)(mapFunc)
Option 3 (TS 4.0): Variadic tuples
function mapRangeVT<T extends Range_>(...rangeArgs: [...T, MapFunc<number>]) {...}

mapRangeVT(1, mapFunc)
mapRangeVT(1, 2, mapFunc)

If you can update to the latest TS version, option 3 probably fits best, as function shape is not changed.

Play sample

Sign up to request clarification or add additional context in comments.

1 Comment

Optional 3 is truly the way I was looking for. Thanks!

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.