Determine the types of values for an object through the use of Generics

After spending a while pondering over this issue, I have yet to discover an elegant solution.

My dilemma begins with an Enum:

export enum Enum {
    A,
    B,
    C,
}

Next, there is an object that utilizes the Enum. While the structure is somewhat predictable in that its value will always be a function returning a string, the uncertainty lies in the fact that the function may accept any number of arguments:

import { A, B, C } from '../enums/';

export const obj = {
    [A]: () => 'example 1',
    [B]: (arg1: string) => 'example 2, arg1: %s',
    [C]: (nr: string, arg2: string) => 'example %s %s',
}

The final piece of the puzzle is a function which leverages obj to fetch specific strings based on its arguments:

const fct = <E extends Enum>(
    code: E,
    ...args: Parameters<(typeof obj)[E]>
) => {
    ...
}

Although everything functions properly, it lacks type safety since every Enum value must be assigned to a value within obj.

If I were to create a basic type, Parameter would not accurately display the arguments of the function:

type ObjectType = { [key in Enum]: (...args: any[]) => string }
Parameters<(typeof obj)[A]> // -> (...args: any[])

Answer №1

To restrict the type of object so that it only accepts keys from Enumeration and values as "functions returning string", you can utilize the satisfies operator (refer to the Record<Keys, Type> utility type) mechanism. Additionally, in function func, you can constrain the generic type parameter E based on the specific keys available within obj, as opposed to any potential Enum key (it may or may not exist) using this setup:

TS Playground

enum Enumeration {
  X,
  Y,
  Z,
}

const object = {
  [Enumeration.X]: () => 'example X',
  [Enumeration.Y]: (arg1: string) => 'example Y, arg1: %s',
  [Enumeration.Z]: (nr: string, arg2: string) => 'example %s %s',
} satisfies Record<Enumeration, (...args: any[]) => string>;

const func = <E extends keyof typeof object>(
  code: E,
  ...args: Parameters<(typeof object)[E]>
) => {};

func(Enumeration.X); // Successful
func(Enumeration.X, "foo"); /* Error (anticipated)
            ~~~~~
Anticipated 1 argument, received 2.(2554) */

func(Enumeration.Y, "foo"); // Successful
func(Enumeration.Y); /* Error (anticipated)
~~~~~~~~~~~
Expected 2 arguments, but received 1.(2554) */


func(Enumeration.Z, "foo", "bar"); // Successful
func(Enumeration.C, "foo"); /* Error (anticipated)
~~~~~~~~~~~~~~~~~~
Expected 3 arguments, but received 2.(2554) */

func(Enumeration.C); /* Error (anticipated)
~~~~~~~~~~~
Expected 3 arguments, but received 1.(2554) */

// …continued.

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

Tips on deactivating a div when a checkbox is selected

I am currently working with a checkbox element in my code: <md-checkbox checked.bind="addEventCommand.allDay" change.delegate="allday()">All Day</md-checkbox> When the above checkbox is true, I want to disable the following ...

Combining ReactJS event handling for onClick and onKeyDown into a single handler for TypeScript

To ensure accessibility compliance, I am incorporating onKeyPress handlers into my application. However, I am facing a challenge with interactive <div /> elements. Here are the event handlers I want to trigger on click: const handleViewInfoClick = ( ...

The style fails to load correctly upon the page's initial loading

I am utilizing <a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="4d26282823603e212429283f0d7b63756378">[email protected]</a> in a <a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="026c677a76 ...

Utilizing a variable to pass props to a component (instead of a static component) within React Router 5

In react-router 5, you can pass props to a child component in this way: <Route path="/" exact render={ props => <MyPage title={myTitle} dataPath={myDataPath} {...props} />} /> However, I am using a route model in my ...

Consider pushing items onto an array only once when the condition is met, instead of adding to the array every

I have been tasked with importing Excel files containing customer orders into my web application. The process involves converting the data in the file into an object of arrays, where each array represents a row from the Excel sheet. Once the data is impor ...

Leverage the power of JavaScript functions within the app.component.ts file of

I have a JavaScript file named action.js and I am trying to incorporate it into an Angular project. After doing some research, I found out that the js file should be placed in the assets folder and the path must be referenced in the scripts array within an ...

Is it necessary for a TypeScript Library's repository to include the JavaScript version?

Is it necessary to include a JavaScript version of the library along with the Typescript repository for consumers? Or is it best to let consumers handle the compilation process themselves? Or should I consider another approach altogether? ...

Unable to retrieve the reflective metadata of the current class instance

Is it possible to retrieve the reflect-metadata from an instance of a class? The documentation provides examples that suggest it should be achievable, but when I attempt to do so, I receive undefined as a result. Strangely enough, when I request the metada ...

Pattern matching for validating multiple email addresses

I need assistance with validating multiple email inputs using regex in Angular. I am looking to enforce a specific format for the emails, such as: Examples: *****@zigurat.com *****@test.com *****@partlastic.com The ***** can be any characters, but the ...

Encountering a Typescript issue while trying to access two distinct values dynamically from within a single object

Currently, I'm developing a component library and facing an issue with a TypeScript error: An Element implicitly has an 'any' type due to the expression of type 'levelTypes | semanticTypes' being unable to index type '{ level1 ...

Problem integrating 'fs' with Angular and Electron

Currently, I am working with Angular 6.0, Electron 2.0, TypeScript 2.9, and Node.js 9.11 to develop a desktop application using the Electron framework. My main challenge lies in accessing the Node.js native API from my TypeScript code. Despite setting "com ...

Modify a particular attribute in an array of objects

I am currently working on an Angular project and dealing with the following array object: { "DATA": [ { "CUSTOM1": [ { "value": "Item1", ...

What is the best way to eliminate the content of an element using javascript/typescript?

The progress bar I'm working with looks like this: <progress class="progress is-small" value="20" max="100">20%</progress> My goal is to use javascript to remove value="20", resulting in: <progre ...

Could someone please help me identify the mistake in this code? I recently created a new class, imported it into a .ts file, and then proceeded to define

Upon checking the console, an error message appeared stating that Recipe was not defined. To resolve this issue, I made sure to include the necessary class definition in a separate file at the end of my code. The import statement: import { Recipe } from ...

IDE flags an error with TypeScript type declarations

Here is how my type definition looks: export type AuthType = boolean | { roles: string[]; assistant?: string[] } | (() => void); Now, I need to check the type of the auth variable and assign a value or execute a function in this line of code: req.all ...

Utilizing Vue class-style components for creating a recursive component

I'm currently working with a class-style component using the vue-property-decorator plugin. I want to create a recursive component that can use itself within its own structure. Here's a snippet of my code: <template> <ul> <li& ...

What is the injection token used for a specialized constructor of a generic component?

I created a versatile material autocomplete feature that I plan to utilize for various API data such as countries, people, and positions. All of these datasets have common attributes: id, name. To address this, I defined an interface: export interface Auto ...

How to retrieve an array stored within a JSON object

I am trying to access a specific array within an object from a JSON file. Here is the snippet of the data I'm dealing with: best-sellers": [ { "title": "Chuteira Nike HyperVenomX Proximo II Society", "price": 499.90, "installmen ...

Typeorm encountered an error when attempting to assign the unknown type to an entity

I'm encountering difficulties while using TypeOrm with TypeScript for a specific project. It appears that TypeScript is unable to recognize a type being returned from a TypeORM entity. @Entity({ name: "users", synchronize: false }) export default c ...

Angular - Resolving the issue of 'property does not exist on type' in TypeScript

Currently, I am following a video tutorial which also has a text version. Despite copying the code exactly as shown in the tutorial, I encountered the following error: Error TS2339: Property 'getEmployees' does not exist on type 'Employ ...