Typescript: Define a set of partially applied functions with a flexible number and variety of input parameters, each producing a function of identical type

I am currently seeking a way to categorize a collection of partially applied functions where only the initial parameter(s) differ. In other words, this group consists of functions that can take any number of parameters of any type, but the first application must always result in a function of type (state: State) => Event[].

For instance, consider a set of functions like this:

const group = { 
  func1: () => (state: State) => Event[],
  func2: (arg: string) => (state: State) => Event[],
  func3: (arg: string, arg2: number) => (state: State) => Event[],
}

All these functions adhere to the following pattern (although not yet updated to accommodate multiple arguments):

export type Command = <T>(arg: T) => (state: State) => Partial<Event>[];

However, when attempting to define the group with typescript as shown below:

const command: Record<string, Command> = {
  func1: () => (state: State) => [{}],
  func2: (arg: string) => (state: State) => [{}],
  func3: (arg: string, arg2: number) => (state: State) => [{}],
};

Typescript raises an error stating that type T is not assignable to type string.

Type '(arg: string) => (state: State) => {}[]' is not assignable to type 'Command'.
  Types of parameters 'arg' and 'arg' are incompatible.
    Type 'T' is not assignable to type 'string'

I understand the reason behind this assignment issue, but I am struggling to determine how I could properly type this grouping of partially applied functions. Essentially, my goal is to ensure that every function in this collection follows the Command type pattern, meaning it should be a partially applied function accepting parameters of any type that ultimately returns a function of type: (state: State) => Event[]

Is achieving such typing feasible? If so, what would be the correct approach?

Answer №1

Does using any in the type declaration and specifying the function parameter later in the group help?

export type Command = (...arg: any[]) => (state: State) => Partial<Event>[];

const command: Record<string, Command> = {
  func1: () => (state: State) => [{}],
  func2: (arg: string) => (state: State) => [{}],
  func3: (arg: string, arg2: number) => (state: State) => [{}],
};

Update

To make the parameters more specific, you can let Typescript infer the function signatures:

export type Command = (state: State) => Partial<Event>[];

const command = {
  func1: (): Command => (state: State) => [{}],
  func2: (arg: string): Command  => (state: State) => [{}],
  func3: (arg: string, arg2: number): Command => (state: State) => [{}],
};

command.func1() // OK
command.func1("test") // Err
command.func2() // Err
command.func2("test") // OK
command.func2([]) // Err
command.func3() // Err
command.func3("test", 2) // OK
command.func3([]) // Err

Alternatively, you can explicitly type the group:

export type Command = (state: State) => Partial<Event>[];
interface CommandsGroup {
    func1: () => Command;
    func2: (arg: string) => Command;
    func3: (arg: string, arg2: number) => Command
}

const command: CommandsGroup = {
  func1: () => (state: State) => [{}],
  func2: (arg: string) => (state: State) => [{}],
  func3: (arg: string, arg2: number) => (state: State) => [{}],
};

command.func1() // OK
command.func1("test") // Err
command.func2() // Err
command.func2("test") // OK
command.func2([]) // Err
command.func3() // Err
command.func3("test", 2) // OK
command.func3([]) // Err

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

Setting up ag-Grid without displaying an empty grid at the start

In the context of an ag-grid, data will only appear if the grid contains some content. //HTML file <form [formGroup]="myForm" (ngSubmit)="search()" > <button type="submit" class="btn btn-default">Search</button> </form> <d ...

Angular 2 - Constructing dates in constructor - Error: Type 'Date' cannot be assigned to type 'string'

In my attempt to generate a fresh date object for an ngx-chart by referencing this specific example, I came across the following code snippet: constructor() { this.data = this.multi.map(group => { group.series = group.series.map(dataItem =& ...

typescript declaring a namespace with a restricted identifier

I have created a custom Http client in typescript with the following definition: declare namespace Http { type HttpOptions = ...; type HttpPromise<T> = ... function get<T>(url: string, options?: HttpOptions): HttpPromise<T>; ...

Error encountered when attempting to modify an Angular expression within a table that is being edited inline

In my table, there is a child component called modal which contains two buttons - save and cancel for inline editing. I am aware that I need to utilize "ChangeDetectorRef", but I am struggling to implement the event "ngAfterViewInit" in my code. An erro ...

webpack is having trouble locating the src file, even though it should not be searching for it in the first place

I'm currently delving into the world of using TypeScript with React and am following a helpful tutorial at: https://blog.logrocket.com/how-why-a-guide-to-using-typescript-with-react-fffb76c61614 However, when attempting to run the webpack command thr ...

The format must be provided when converting a Spanish date to a moment object

I am working on an Angular 5 project where I am converting dates to moment objects using the following code: moment(date).add(1, 'd').toDate() When dealing with Spanish locale and a date string like '31/7/2018', the moment(date) funct ...

Typescript Array does not adhere to correct data type

Why does the code below fail to transpile when pushing a new instance of class B into an array that is typed as only accepting instances of class A? class A {}; class B {}; const arr: A[] = []; arr.push(new B()); ...

Ways to incorporate conditional checks prior to running class methods

Seeking input on handling async data retrieval elegantly. When initializing a class with asynchronous data, I have been following this approach: class SomeClass { // Disabling strictPropertyInitialization private someProperty: SomeType public asy ...

Error TS2540: Cannot update the style property as it is designated as read-only

I ran into an issue while working on my TSX markup. The TS typechecker in Vim is giving me the error message 2540: Cannot assign to style because it is a read-only property when I try to create a textarea element. It's odd that textarea.style is read- ...

With a GroupAvatar, my Avatar named "max" likes to dance to the beat of its own drum rather than following the rules of my

I am currently working on creating an AvatarGroup using MaterialUi. I have successfully applied a style to all my avatars, except for the avatar that is automatically generated by AvatarGroup when the "max" parameter is defined. const styles = makeStyl ...

Tips for utilizing the latest hook feature in Typegoose

After adding a pre hook on updateOne events, I noticed it functions differently compared to save events... I believe this discrepancy is due to the fact that the update command typically includes a matcher as its first argument. I attempted to capture the ...

Enhancing Angular Material forms with custom background colors

I'm new to Angular and Angular material, still learning the ropes. I have been trying to create a form and needed to change the background color to Red. However, when I attempted to do so, the red color ended up covering the entire form instead of ju ...

How can I subtract a value from my array in Angular?

I've been troubleshooting this problem for a while now and I'm hoping that someone here can assist me with finding a solution. The issue at hand involves an array object containing various values such as id, title, amountCounter. Specifically, t ...

Error message: "Unidentified variable in the code snippet from MUIv5 sample."

Achieving the Objective To implement a drawer sidebar in MUI5 that can be toggled open and closed by the user, I am exploring the documentation for the Drawer component as well as referencing an example. Encountering an Issue Upon copying the code from ...

What is the process for allowing users to select multiple choices in a headless-ui combobox/autocomplete feature?

Currently, I am implementing headless-UI combobox/autocomplete and I'm interested in enabling multiple options selections with this component. Does anyone have any insights on how to accomplish this? ...

What is the best way to transform a ternary operation into an Enum Map with custom properties

I'm faced with the challenge of styling a button based on the selection made in a select box. The code snippet I have currently is as follows: const buttonStyles = { backgroundColor: buttonStyle === 'Black' ? colors.interactiveForeground ...

What are the steps to set up NextJS 12.2 with SWC, Jest, Eslint, and Typescript for optimal configuration?

Having trouble resolving an error with Next/Babel in Jest files while using VSCode. Any suggestions on how to fix this? I am currently working with NextJS and SWC, and I have "extends": "next" set in my .eslintrc file. Error message: Parsing error - Can ...

How can I customize both the message and icon in a Dynamic Dialog component using Angular PrimeNG within a single component?

Can someone help me with styling the message and icon properties of just a single dialog in this .ts file? I'm encountering an issue where the provided .scss code is affecting the styling of all dialogs throughout the entire app, which is not what I i ...

I attempted to implement a CSS and Typescript animation for a sliding effect, but unfortunately, it isn't functioning

So I'm encountering an issue with this unique ts code: {/* Mobile Menu */} <div className="lg:hidden"> <button className="flex items-center w-8" onClick={toggleMenu}> {isMobileMenuOpen ? ( ...

Tips for designing a custom TypeScript 5 property decorator

I have a decorator in TypeScript: const bindMethod = (method: any): PropertyDecorator => ((target: any, name?: PropertyKey): any => { if(name === undefined) { throw new Error('Bound decorator must be used with a property name.& ...