"Specifying the data type of function parameters in parts

Trying to define a type for a function "factory", the issue arises when the number of arguments in the callback is unknown beforehand. Take a look at the following factory builder:

type Fn = (...args: any[]) => any

function apply<F extends Fn>(fn: F, ...applyArgs: Parameters<F>) {
   return (...args: Parameters<F>) => fn(...(applyArgs || []), ...(args || []))
}

This pattern is quite common, as seen in this example factory:

function add(a: number, b: number) {
   return a + b
}

// Error occurs here, Parameters expects 2 args but only got 1
const plus2 = apply(add, 2)

// Another error due to the parameter mismatch
plus2(2) // 4

The root issue is that the Parameters utility type requires all parameters to be used, not just some of them. The solution involves creating two types - ApplyArgs for initial parameters and RestArgs for remaining ones.

I attempted to define possible numbers of args manually, which did result in correct types for the params:

Type definitions...

While this method somewhat works:

function add(a: number, b: number) {
   return a + b
}

// Now it works correctly
const plus2 = apply(add, 2)

// Works partially, but triggers TypeScript error
plus2(2) // 4

Although the rest params are technically undefined where applicable, TypeScript still expects the specified length for params. This clunky approach is not scalable with an infinite amount of potential params.

In conclusion, without the ability to recursively pass an index for inferring array indexes from a specific point, such as "

type Until<Id> = [infer Params[0:Id]
, I'm uncertain if this challenge is even achievable.

You can access the shared TypeScript playground here.

Answer №1

Initially, let's revamp the ApplyArgs type (although the name could definitely be improved):

type UpTo<A> = A extends readonly [...infer Rest, any] ? A | UpTo<Rest> : A;

type T = UpTo<[1, 2, 3]> // [1, 2, 3] | [1, 2] | [1] | []

Next, introduce a type to skip over the specified parameters:

type Skip<S extends any[], T> = T extends [...S, ...infer Rest] ? Rest : never;

This leads us to a clear and comprehensible function signature:

function apply<F extends (...args: any[]) => any, Params extends UpTo<Parameters<F>>>(fn: F, ...applied: Params) {
   return (...args: Skip<Params, Parameters<F>>) => fn(...(applied || []), ...(args || [])) as ReturnType<F>;
}

Explore in 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

Unexpected issue encountered during the Angular 9 compilation process

Since migrating to Angular 9, I've encountered an issue with my feature branch after a rebase. Trying to switch to develop and update it using pull origin develop, everything seemed fine until I came across this error that's leaving me puzzled: h ...

What is the best way to connect input values with ngFor and ngModel?

I am facing an issue with binding input values to a component in Angular. I have used ngFor on multiple inputs, but the input fields are not showing up, so I am unable to push the data to subQuestionsAnswertext. Here is the code snippet from app.component ...

Managing the onChange event for a MaterialUI dropdown component

I'm encountering an issue with validating the MaterialUI TextField component (Country list) wrapped with Autocomplete. I am trying to use the onChange event to enable the Submit button when the country field is filled in. However, the problem arises w ...

The test.ts file does not contain any type definitions

While I am able to successfully utilize my types in .ts files, I am facing difficulties in understanding why it's failing in .test.ts files, even though both files are located in the same folder. Check out the code in the .ts file below: https://i.s ...

The "next" method of the Angular BehaviorSubject is malfunctioning

I previously wrote a code in Angular 4 that was functioning flawlessly, however, after migrating to Angular 6, a part of it seems to be broken. I would greatly appreciate any assistance with this issue. One problematic area is within the AuthService class ...

What is the method to dynamically add an error to a FormGroup control using programming?

I am working with a dynamic FormGroup and I need to add an error to a form control programmatically. However, the current method I know of replaces any existing errors as shown below: this.userForm.controls.username.setErrors({ 'exists': &apos ...

Generate a type error if the string does not correspond to the key of the object

How can I trigger a type error in TypeScript 4.4.3 for the incorrect string 'c' below, which is not one of the keys of the object that is passed as the first parameter to the doSomething method? const doSomething = ({ a, b }: { a: number, b: stri ...

Is there a way for me to bypass adding the label if it already exists in my state, but still include the new value?

I am currently facing an issue with a dropdown select field where I can choose various attribute values. The problem arises when attempting to save the selected data in the state, as the label appears twice and I only require it once. My goal is to exclude ...

What causes *ngIf to display blank boxes and what is the solution to resolve this problem?

I am currently working on an HTML project where I need to display objects from an array using Angular. My goal is to only show the objects in the array that are not empty. While I have managed to hide the content of empty objects, the boxes holding this co ...

ways to convert to a specific subtype within a union

type example = { name : string | number | null } type processNumber = { name : number } const a : example = { name : 123 } as const function PROCESS (input : processNumber) { console.log(input.name) } PROCESS(a); I am facing an issue whe ...

Error encountered: 'applePaySession.completeMerchantValidation' is not a valid object reference when attempting to process a successful apple pay payment

So, I'm having an issue with the user's payment going through but encountering undefined value when checking compatibility. I've been trying to debug this problem in my code snippet below: setCanDisplayApplePay() { var client = n ...

Encountering the "Unrecognized teardown 1" error when subscribing to an Observable in Typescript and Angular2

Having trouble with using an Observable in my Angular2.rc.4 Typescript app. Check out the plunker for it here: https://embed.plnkr.co/UjcdCmN6hSkdKt27ezyI/ The issue revolves around a service that contains this code: private messageSender : Observable< ...

In app.component.ts, the Transloco translateService.translate function is failing to function properly

I have encountered an issue where when I put the following code in my app.component.ts constructor, it does not work: alert(this.translateService.translate('navigation.dashboard')); But interestingly, if I place the same code in a submodule, it ...

Utilize JSON values in Powershell as default parameters

One of my challenges is writing a script that utilizes parameters with default values stored in a json file. I've encountered an issue where Powershell doesn't recognize param() if it isn't the first line of code within the script. However, ...

Solving the issue of interconnected promises in Angular services

I am utilizing a DynamoDB service within my Angular project which returns a promise through a series of promises. This process involves retrieving a subId from Cognito and then passing that subId to a DynamoDB get query: async getUserObject(): Promise< ...

Can I integrate @types/pkg into my custom library to automatically have types included?

Imagine I am creating a library that utilizes types from the Definitely Typed repository (such as @types/pkg). Would it be feasible for my package to automatically include these types when installed, eliminating the need for consumers to separately instal ...

Passing parameters in React classes is a crucial aspect of creating

Within a project I am currently working on, there is a const defined for the page header which takes in parameters and utilizes the information: interface UserProps { user?: { name: string, image: string }, loading?: boolean, error?: E ...

Service call delay not displayed on screen

I have a function that I execute in my component's ngOnInit lifecycle hook. This function calls a service to fetch data and populate an array. Once that array is filled, I then call another service method using the data from the first array to populat ...

Angular Material 2: Sidenav does not come with a backdrop

I'm encountering an issue with the SideNav component while developing a website using Angular 2. The SideNav has 3 modes, none of which seem to affect what happens when I open it. I am trying to make the backdrop display after opening. Even though t ...

Using the OR notation to declare the property name with 2 types is not functioning as expected for me

I'm having trouble with this solution. Here is the link to the source: Is it possible to declare a property with multiple types using the OR notation like this? export interface OnboardingSchoolModel { level?: string | number; school?: stri ...