Creating reusable TypeScript function argument types

There is a function that I have defined in the following way:

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 aim to ensure that this function's arguments are typed and can be reused. So, I created the following:

type Range = Parameters<typeof getRangeBounds>;

I plan for the type Range to be reusable in a few more functions, such as range and mapRange, which will have the following signatures respectively:

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

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

How can I ensure that these functions adhere to the contract of Range and also allow for additional arguments in certain functions like the modified mapRange above?

Edit: I have resolved the compilation error mentioned earlier, so the revised version of mapRange appears as follows:

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

However, now I need to call the function in this manner:

mapRange([start, stop, step])

Answer №1

Here are several approaches to include additional parameters in the Range function for other functionalities:

Approach 1: Rearrange rest parameter to be the final element
function mapRangeRest(mapper: MapFunc<number>, ...rangeArgs: Range) { ... }

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

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

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

If upgrading to the latest TS version is feasible, option 3 may be the most suitable choice since it does not alter the function's structure.

Try it out

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Issue: ReactJS - $npm_package_version variable not functioning properly in build versionIn the current

After trying this suggested solution, unfortunately, it did not work for my specific case. The React application I am working on was initialized with CRA version 5.0.1 and currently has a version of 18.2.0. Additionally, the dotenv version being used is 1 ...

Error: The URL constructor is unable to process /account as a valid URL address

Working on a new social media app using appwrite and nextjs, encountering an error "TypeError: URL constructor: /account is not a valid URL" upon loading the website. Here's the current file structure of my app: File Structure Below is the layout.tsx ...

Do we need a peer dependency specifically for TypeScript typings or is it optional?

My TypeScript library includes a React component, and one of the optional features allows users to pass an instance of a Redux store as a prop for Redux integration. <Component reduxStore={store}></Component> Since this feature is optional, I ...

The Vite proxy server will not modify POST requests

When I set up a proxy using Vite, I noticed that it only handles GET and HEAD requests. I'm looking to have other request methods proxied as well. In a new Vite React project - the only modification I made was in vite.config.ts import { defineConfig ...

Is it possible to use square brackets in conjunction with the "this" keyword to access a class property using an expression?

export class AppComponent implements OnInit { userSubmitted = false; accountSubmitted = false; userForm!: FormGroup; ngOnInit(): void {} onSubmit(type: string): void { this[type + 'Submitted'] = true; if(this[type + 'For ...

Angular - Electron interface fails to reflect updated model changes

Whenever I click on a field that allows me to choose a folder from an electron dialog, the dialog opens up and I am able to select the desired folder. However, after clicking okay, even though the folder path is saved in my model, it does not immediately s ...

Using a pipe filter to implement a search feature in an Ionic search bar

Hey everyone, I'm facing a little issue here. I created a pipe filter to sort through some data, but now I need to include two more filters and I'm not sure how to go about it within this pipe. Below is an example of the pipe I have created: ...

Passing information from the main component to a service through API connections

Currently, I am in the process of developing a website dedicated to showcasing the top 20 highest-rated Sci-fi movies. The main component on the homepage leverages a GET request via a service to fetch an array of objects containing the movie data. This mov ...

Creating an empty TypeScript variable with type FileList can be achieved by declaring the variable and initializing it with

After completing a coding test that required building a react app for uploading files using Typescript, I encountered a dilemma. Specifically, I needed to use the useState hook to store the uploaded file and set its default value. Typically, setting the de ...

Combining Arrays Together in TypeScript

I am in need of a solution to merge two arrays into one using TypeScript. First Array Object: export interface Item{ Label : string, Code : string, Price : number, } Second Array Object: export interface Amou ...

I am looking for a way to transfer data collected from an input form directly to my email address without the need to open a new window. As of now, I am utilizing angular

Is there a way to send this data to my email address? I need help implementing a method to achieve this. {Name: "John", phoneNumber: "12364597"} Name: "John" phoneNumber: "12364597" __proto__: Object ...

Encountered issues while trying to utilize wasm function within Vue framework

When attempting to integrate wasm with Vue, I encountered a frustrating issue where the startQuorum function in my wasm file could not be located. import { Go } from './wasm_exec' import quorumWasmUrl from './lib.wasm' export const sta ...

Troubleshooting Node.js import module errors

I have just discovered two files that I created using the TS language specification manual (on page 111). The first file, called geometry.ts, contains the following code: export interface Point { x: number; y: number }; export function point(x: number, y ...

Tips for ensuring the HTML checkbox element is fully loaded before programmatically selecting it

When a user accesses the page, I want certain checkboxes to be automatically checked. To achieve this, I am storing the IDs of the HTML checkbox elements in a service. Upon entering the page, the service is utilized to retrieve an array containing these ID ...

What is the best approach to handle Flow types for component props and getDerivedStateFromProps when the props are not the same

Having a Component with its props, an additional prop is added for getDerivedStateFromProps. The issue arises when setting the props with the additional one, throwing an error that the prop is not being used. Conversely, setting it without the extra prop c ...

When trying to pull a component from Svelte, I receive an error message stating "Selection Range

I'm still relatively new to svelte, so I might be handling things incorrectly. Whenever I attempt to separate my button component, regardless of whether I name the component ./Button.svelte, ./Button, Button.svelte, or try variations with capitalizat ...

Encountering an error with TypeScript generic parameters: Expecting '?' but receiving an error message

As a newcomer to TypeScript, I am currently exploring the use of generic type parameters. I have encountered an error message: '?' expected while working on a function and a type that both require type arguments. The issue seems to be in the Inpu ...

Executing functions in Vue TypeScript during initialization, creation, or mounting stages

Just a few hours ago, I kicked off my Vue TypeScript project. I've successfully configured eslint and tslint rules to format the code as desired, which has left me quite pleased. Now, I'm curious about how to utilize the created/mounted lifecycl ...

The Fusion of Apollo GraphQL Server and TypeScript: A Match Made

Lately, I've been immersed in a project that utilizes the node.js + express + typescript + Apollo server stack. During my research on Apollo client, I came across the TypeScript section, but surprisingly found little information regarding TypeScript f ...

How to correctly type socket events when developing a customized useSocket hook in TypeScript?

Both my socket server and socket client are set to listen for a specific range of events. Below are the definitions for these socket events: import { Server } from "socket.io"; import { Socket } from "socket.io-client"; import { Disconn ...