Creating callback functions that vary based on input variables

Consider the following code snippet, which may seem somewhat contrived:

arbitraryFunction(
    // Input that is dynamically generated
    [
        returnValue("key1", "a"), 
        returnValue("key2", 1),
        returnValue("key3", ()=>{})
    ],

    // Callback function with parameters matching the input types
    (value : {key1: string, key2: number, key3: Function} )=>{
        return value 
    }

)

The goal is to specify the type of the value parameter in the callback based on the provided input.

For instance, this callback function would be invalid:

// key1 should be a string, not a number!
(value : {key1: number} )=>{}

I've attempted to use generics without success. Is there anyone who can provide some insight into whether this is achievable?

Answer №1

Absolutely! It is feasible to achieve this task. The key lies in implementing recursive array traversal within your generic functions to iterate through the ReturnValues array and construct parameters for the callback function.

Feel free to inquire if you need further elucidation on any aspect, as there's quite a bit to unpack here!

function returnValue<K extends string, T>(key: K, type: T): [K, T] {
    return [key, type];
}

type ReturnValue = ReturnType<typeof returnValue>;

type GenerateCallbackParams<I extends readonly ReturnValue[], P = {}> =
    // Base case where we have one item left in I
    I extends  readonly [infer R]
        ? R extends [infer K, infer T]
            ? K extends string 
                // Merge params with K: T
                ? P & { [key in K]: T }
                : P
            : never
        // Handling multiple array elements in I
        : I extends readonly [infer R, ...(infer Tail)]
            ? R extends [infer K, infer T]
                ? K extends string
                    ? Tail extends ReturnValue[]
                        ? GenerateCallbackParams<Tail, P & { [key in K]: T }>
                        : never
                    : never
                : never
            : never;

function arbitraryFunction<I extends readonly ReturnValue[]>(inputParams: I, callback: (params: GenerateCallbackParams<I>) => GenerateCallbackParams<I>) {

}

// Declaration of const is necessary to prevent TS from changing the type inside the array
const params = [
    returnValue("key1", "a"), 
    returnValue("key2", 1),
    returnValue("key3", ()=>{})
] as const;

arbitraryFunction(
    // Dynamically generated input
    params,

    // Callback function with typed parameters based on input
    ({ key1, key2, key3}) => {
        typeof key1; // string
        typeof key2; // number
        typeof key3; // () => void
        return { key1, key2, key3 };
    }
)

Navigate to playground

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

Importing libraries in TypeScript and JavaScript are not done in the same manner

As I create my own library, I aim for it to be compatible with both javascript and typescript. tsconfig.json { "compilerOptions": { "target": "es2017", "module": "commonjs", &qu ...

The origin of the Angular img src becomes blurred when invoking a function

I want to dynamically change the image src by calling a function that returns the image path. However, when I attempt to do so using the code below, the image element displays as <img src(unknown)/> component.ts: getMedia(row) { this.sharedData ...

Even when using module.exports, NodeJS and MongoDB are still experiencing issues with variable definitions slipping away

Hello there, I'm currently facing an issue where I am trying to retrieve partner names from my MongoDB database and assign them to variables within a list. However, when I attempt to export this information, it seems to lose its definition. Can anyone ...

Angular 2 Unit test issue: Unable to resolve parameters for 'RequestOptions' class

I am currently working on testing a simple component that has some dependencies. One of the requirements is to provide certain providers for the test. /* tslint:disable:no-unused-variable */ import { By } from '@angular/platform-browser&ap ...

What is the best way to retrieve the href attribute when working with cheerio?

Is there a way to retrieve the link using Cheerio in this code snippet? <div class="someClass"> <a href="someLink">Link</a> </div> I attempted to do so, but unfortunately it was unsuccessful. let link = $(&a ...

Typescript: Streamline the process of assigning types to enum-like objects

One common practice in JavaScript is using objects as pseudo-enums: const application = { ELECTRIC: {propA: true, propB: 11, propC: "eee"}, HYDRAULIC: {propA: false, propB: 59, propC: "hhh"}, PNEUMATIC: {propA: true, propB: ...

Tips for preserving data upon page refresh in angular 2/4

As a newcomer to Angular2/4, I am facing an issue where the details fetched and saved in my interface are disappearing upon interface refresh. How can this problem be resolved without losing the interface details after a refresh? Here is my Login.componen ...

The Angular custom modal service is malfunctioning as the component is not getting the necessary updates

As I develop a service in Angular to display components inside a modal, I have encountered an issue. After injecting the component content into the modal and adding it to the page's HTML, the functionality within the component seems to be affected. F ...

Guide to Validating Fields in Angular's Reactive Forms After Using patchValue

I am working on a form that consists of sub-forms using ControlValueAccessor profile-form.component.ts form: FormGroup; this.form = this.formBuilder.group({ firstName: [], lastName: ["", Validators.maxLength(10)], email: ["", Valid ...

Utilizing client extension for Postgres with Prisma to activate RLS: A step-by-step guide

Recently, I attempted to implement client extension as advised on Github. My approach involved defining row level security policies in my migration.sql file: -- Enabling Row Level Security ALTER TABLE "User" ENABLE ROW LEVEL SECURITY; ALTER TABLE ...

Angular Material (8) error code S2591: The variable 'require' is not defined in the current scope

Currently, I am attempting to record the date and time in the JavaScript console. Despite the code successfully logging the dates, an error message persists: Note: The code is functioning properly, with the dates being displayed in the console. It is only ...

The error occurred in Commands.ts for Cypress, stating that the argument '"login"' cannot be assigned to the parameter of type 'keyof Chainable<any>))`

Attempting to simplify repetitive actions by utilizing commands.ts, such as requesting email and password. However, upon trying to implement this, I encounter an error for the login (Argument of type '"login"' is not assignable to parameter of t ...

Is it acceptable to include a @types library as a regular dependency in the package.json file of a Typescript library?

Should the library also be compatible with Typescript projects? I am developing a Typescript library that utilizes node-fetch and @types/node-fetch, which will be shared through an internal NPM registry within the company. If I only include @types/node-f ...

When attempting to utilize the Next.js Head component in a location other than _document, the page experiences

Currently, I am in the process of integrating Next.js with Typescript and Material UI. Despite the abundance of tutorials available online for setting up Next.js with Material UI, I have encountered a commonality among them where they all provide identical ...

Having trouble receiving a blob response using HttpClient POST request in Angular 9?

I'm encountering an issue while attempting to receive a zip file as a blob from an HTTP POST request. However, the resolved post method overload is not what I expected. const options = { responseType: 'blob' as const }; Observable<Blob ...

Ways to prevent a user from reaching a specific page by entering the URL in a react and typescript application

Is there a way to restrict access to a specific page with the URL "myurl/view"? I want only admin users to be able to view this page, while preventing other users from accessing it. Currently, when the view button is clicked, it redirects to the URL "/vie ...

The anticipated data type is derived from the attribute 'value' defined within the 'IntrinsicAttributes & ProviderProps<IProductContext>' type

During the creation of an e-commerce website, I decided to use React Typescript. However, I encountered an issue with Contexts while trying to export my state in the Provider value. Thank you for any assistance provided. ERROR Type '{ products: IP ...

Creating dummy objects from a specific data type in Typescript for the purpose of testing

I'm exploring ways to streamline the creation of mock data for unit testing within an Angular solution. Currently, I am defining interfaces such as: export interface ReferenceDataItemCommon { codeDescription?: string; code: string; deleted?: boo ...

What is the reason for my algorithm's inability to work with this specific number?

I'm currently working on creating an algorithm to compute the sum of prime numbers that are less than or equal to a specified number. Below is my attempt: function calculatePrimeSum(num) { // initialize an array with numbers up to the given num let ...

Creating a TypeScript frozen set: A step-by-step guide

Imagine having a group of values that you want to protect from being edited, as shown below: // These values should not be editable. const listenedKeys = new Set(['w', 'a', 's', 'd']) // This value can be accessed w ...