Creating a Javascript Function with Dual Meanings for the First Argument
Scenario
We want to create a range
function that accepts multiple arguments with this type of interface.
export function range(
start: number,
end: number,
step?: number,
): Iterable<number>;
When the function is called with more than one parameter ( range(10,20,2)
), the above interface is used.
However if we called the function with only one argument ( range(10)
), then we want start to default to 0
and step to default to 1
.
Approach
We will use the range
function from Lit Element to illustrate this.
This is how it is implemented.
/**
* Returns an iterable of integers from `start` to `end` (exclusive)
* incrementing by `step`.
*
* If `start` is omitted, the range starts at `0`. `step` defaults to `1`.
*
* @example
*
* ```ts
* render() {
* return html`
* ${map(range(8), () => html`<div class="cell"></div>`)}
* `;
* }
* ```
*/
export function range(end: number): Iterable<number>;
export function range(
start: number,
end: number,
step?: number,
): Iterable<number>;
export function* range(startOrEnd: number, end?: number, step = 1) {
const start = end === undefined ? 0 : startOrEnd;
end ??= startOrEnd;
for (let i = start; step > 0 ? i < end : end < i; i += step) {
yield i;
}
}
When end
is undefined
start becomes zero. The step
parameter is initialized to 1
in the function parameter declaration.