Tips for creating a versatile function in TypeScript that accepts either a single value or an array of values for two parameters

I'm currently working on a task to develop a versatile function that accepts a parameter called hashMapName, another parameter called 'keys' which can be either a string or an array of strings, and a callback function that will return either a single value of type T or an array of values of type T.

The function should return T if the key is a string and T[] if the key is a string[].

Here is the code I have attempted:


export function getData<K extends string | string[], T>(
hashMapName: string,
keys: K extends string[] ? string[] : string,
serviceCallBack: K extends string[] ? () => Promise<T[]> : () => Promise<T>
): Promise<T> {
return Array.isArray(keys)
? getDataForKeys<T>(hashMapName, keys, serviceCallBack)
: getDataForKey<T>(hashMapName, keys, serviceCallBack);
}

However, I'm encountering a TypeScript error regarding the 'keys' parameter in the getDataForKey function.

Error:

Argument of type 'K extends string[] ? string[] : string' is not assignable to parameter of type 'string'.
Type 'string | string[]' is not assignable to type 'string'.
Type 'string[]' is not assignable to type 'string'.
Type 'string | string[]' is not assignable to type 'string'.
Type 'string[]' is not assignable to type 'string'.

Update 1:

Below are the declarations for the getDataForKeys and getDataForKey functions.


declare function getDataForKey<T>(
hashMapName: string,
key: string,
serviceCallBack: () => Promise<T>
)

declare function getDataForKeys<T>(
hashMapName: string,
key: string[],
serviceCallBack: () => Promise<T[]>
)

Since we strictly adhere to the noExplicitAny policy, we are unable to utilize the 'any' keyword for the functional parameters.

Following the suggestion provided by @Dmitriy, I am now facing the following issue.

Argument of type '(() => Promise<T[]>) | (() => Promise<T>)' is not assignable to parameter of type '() => Promise<T[]>'.
Type '() => Promise<T>' is not assignable to type '() => Promise<T[]>'.
Type 'Promise<T>' is not assignable to type 'Promise<T[]>'.
Type 'T' is not assignable to type 'T[]'

Answer №1

Consider implementing overloaded functions instead of conditional types to handle this specific scenario:

declare function fetchSingleData<T>(...args: any[]): Promise<T>;
declare function fetchMultipleData<T>(...args: any[]): Promise<T[]>;


export function fetchData<T>(
  dataStore: string,
  dataKeys: string,
  fetchCallback: () => Promise<T>
): Promise<T>
export function fetchData<T>(
  dataStore: string,
  dataKeys: string[],
  fetchCallback: () => Promise<T[]>
): Promise<T[]>
export function fetchData<T>(
  dataStore: string,
  dataKeys: string | string[],
  fetchCallback: (() => Promise<T[]>) | (() => Promise<T>)
): Promise<T> | Promise<T[]> {
  return Array.isArray(dataKeys)
    ? fetchMultipleData<T>(dataStore, dataKeys, fetchCallback)
    : fetchSingleData<T>(dataStore, dataKeys, fetchCallback);
}

fetchData("foo", "fooo", async () => "bar"); // works
fetchData("foo", ["fooo"], async () => ["bar"]); // works

fetchData("foo", ["fooo"], async () => "bar"); // error

// This is also valid as T is not restricted to non-array types
fetchData("foo", "fooo", async () => ["bar"]); 

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

Combining AddClass and RemoveClass Functions in Mootools Event Handlers

I am currently in the process of creating a CSS animation, and one aspect involves changing the class name of the body at specific intervals. Since I am relatively new to Mootools (and JavaScript in general), my approach has been to add/remove classes to ...

Ways to conceal a grid item in Material UI framework

My goal is to hide a specific grid item for a product and smoothly slide the others in its place. Currently, I am using the display:none property but it hides the item instantly. I have already filtered the products and now I want to animate the hiding of ...

Error encountered: Unexpected 'o' token in JSON parsing

Although this issue has been discussed numerous times before, I am struggling to identify the error in my code. The error message I am receiving is 'Uncaught SyntaxError: Unexpected token o' Below is the ajax code I am using: $.ajax({ type: ...

What is the best way to implement a unique function in an angularjs directive?

Is it possible to execute a custom function when clicking on the checkbox of a table row shown below? I am using the Angular Smart Table directive and need to be able to store the rowid or another property of the rows when the checkbox is clicked. app.dir ...

Step-by-step guide on integrating a specific location into Google Maps using React.js

I'm in the process of revamping my website using Reactjs. I want to incorporate a specific Google location with reviews on the map, similar to how it appears on this example (My current website is built on Wordpress). As of now, all I've been ab ...

The AJAX response is shown just a single time

My code is designed to send an ajax request when a form is submitted, specifically a search module. It works perfectly the first time the form is submitted, highlighting the table when data is returned. However, I am only able to see the effect once, as th ...

Separate the selected option in the TEXTAREA by commas to make it easier to

Can you assist me with integrating this example? I have the following elements: When adding a textarea, I require an option to be selected and separated by a comma. For instance: Here I will select an option: Subsequently, this chosen option must be ad ...

Combining Multiple Pie Charts with a Line Chart in Highcharts

Can anyone provide guidance on creating a chart similar to the one shown in the Highcharts library? https://i.sstatic.net/BoX4i.jpg ...

Adjusting the dimensions of a table

I've been utilizing jQuery datatable and I am facing a challenge where the table width extends beyond the container it should be contained in. I've attempted several solutions to fix this issue: 1. Setting the sWidth option on both the table an ...

Storing a component in browser storage using JavaScript and Angular

I am currently working on developing an Angular application that allows users to "favorite" a business card and store it in local memory. I am facing challenges with actually storing the clicked element in the browser's local memory. Furthermore, I f ...

Retrieving URL parameters within an API route handler in Next.js

Within my client component called GetUserInfoButton, I initiate a GET request using the URL format of http://localhost:3000/test/users/[id]. The [id] in this URL is represented by an alphanumeric sequence similar to MongoDb. My intention within the file a ...

Tips for Keeping a Responsive Image at the Forefront of a Text-Image Layout as You Scroll

I'm currently in the process of creating a website where text appears on the left side with an accompanying image on the right. The challenge I'm encountering is ensuring that as users scroll, the image adjusts dynamically based on the associated ...

How to update an object property in React using checkboxes

I am currently navigating the world of react and have encountered a challenging issue. I am in the process of developing an ordering application where users can customize their orders by selecting different ingredients. My approach involves using checkboxe ...

Eslint was unexpectedly unable to detect any errors in the .ts files

After creating a SvelteKit project with npm create svelte@latest, I included some .ts files for a particular library. However, when running eslint ., it fails to detect any errors. The default eslint config generated from Svelte is as follows: .eslintrc. ...

Using Typescript for the factory design pattern

My goal is to develop a factory for generating instances of MainType. To achieve this, I want to reuse existing types (specifically the same instance) which are stored in the ItemFactory. class BaseType { } class MainType extends BaseType { } class It ...

Attempting to employ jQuery to generate a text input that allows for inputting multiple incorrect answers

I am putting together a webpage for a friend who has allergies. The idea is that users can input a food item, and the page will indicate whether or not my friend is allergic to it. I have compiled an array of his food allergies, and the goal is for the pag ...

Utilize esbuild to monitor for any modifications, recompile the code, and automatically restart the express server

In my endeavor to develop a basic SSR-powered project using express + react, I find the need to monitor frontend and backend scripts concurrently in the development process. The primary objective is to utilize express routes in directing to react page com ...

Accessing specialized properties of a generic object

Is there a way to gather various 'generic' objects into a collection without a common superclass? If so, how can their shared properties be accessed? For instance: class MyObject<T> { public T Value { get; set; } public string Name ...

Identifying and detecting Label IDs when clicked using the for tag

I am facing an issue with labels and input fields in my code. I have multiple labels that trigger the same input field, but I want to know which specific label triggered the input field. <label id="label1" for="input1">Document1</label> <la ...