Is it possible for TypeScript to convert a generic enum type into a string at runtime?

Enumerations and interfaces are an important part of my codebase:

enum EventId {
  FOO = 'FOO',
  BAR = 'BAR',
}

interface EventIdOptionsMap {
  [EventId.FOO]: {
    fooOption: string;
  },
  [EventId.BAR]: {
    barOption: number;
  }
}

interface EventRequest<K extends EventId> {
  eventId: K;
  options: EventIdOptionsMap[K];
}

To ensure type safety, I often create objects like this:

const test: EventRequest<EventId.FOO> = {
  eventId: EventId.FOO,
  options: {
    fooOption: 'test',
    good: true, // this would not cause an error
  }
}

Despite the benefits, I find myself typing EventId.FOO twice. I wish there was a way to streamline this process, such as through a utility function:

function generateEvent<K extends EventId>(
  eventId: K,
  options: EventIdOptionsMap[K]
): EventRequest<K> {
  return {
    eventId,
    options
  };
}

Unfortunately, even with the utility function, I still need to specify the enum twice for it to work:

const event = generateEvent<EventId.FOO>(EventId.FOO, {
  fooOption: 'test'
});

// With certainty, `event` is of type `EventRequest<EventId.FOO>`

This redundancy in specifying the enum both as a generic type and as a runtime argument bothers me. Surely, there must be a more efficient way to achieve the same level of type safety without repeating ourselves?

Considering that enums have a presence at runtime, I wonder if there's a method to communicate to TypeScript that "this type corresponds to an enum, therefore usable at runtime." This would potentially eliminate the need for dual enumeration declaration.

Duplicating specifications is counterproductive. Are there alternative approaches to reaching the desired outcome without this duplication? I aim to simplify our object creation process to reduce boilerplate.

If you know of any strategies that could help, please share your insights.

Answer №1

If you simply omit the type parameter, TypeScript will automatically determine it:

const event = createEvent(EventId.FOO, {
  fooOption: 'testing'
});

To see an example, visit this link

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

Show a roster of individuals by inputting values that will populate the list with their names

I'm attempting to showcase a list of users by taking the value from an input and using it as a parameter in a get() method. After receiving the response from the get() method, I am pushing it into an object and then trying to display this object in th ...

Typescript overloaded function parameters explained

I am currently working on the following code snippet: import React from "react"; interface BaseFormValue { name: string; } export interface NewFormValue extends BaseFormValue { email: string; } export interface ExistingFormValue extends Ba ...

Best Practice for Using *ngIf in Angular (HTML / TypeScript)

In the past, I frequently used Angular's *ngIf directive in my HTML pages: <p *ngIf="var === true">Test</p> (for instance) However, there have been instances where I needed to perform multiple checks within the *ngIf directive ...

I am looking for guidance on removing the bottom line from the ionic 4 segment indicator. Any advice or tips on

.segment-button-indicator { -ms-flex-item-align: end; align-self: flex-end; width: 100%; height: 2px; background-color: var(--indicator-color); opacity: 1; } I am a beginner in hybrid app development and ...

Inter-component communication in Angular

I am working with two components: CategoryComponent and CategoryProductComponent, as well as a service called CartegoryService. The CategoryComponent displays a table of categories fetched from the CategoryService. Each row in the table has a button that r ...

Tips for invoking a function from one React component to another component

Currently, I am working on two components: one is Game and the other is PickWinner. The Game component serves as the parent component, from which I need to call the pickWinner function in the PickWinner component. Specifically, I want to trigger the startP ...

Several cucumber reports are showing an error message containing special characters

I am encountering an issue in the multiple cucumber report where error messages are being displayed with special characters. Is there a way to format them properly? I am currently learning Playwright, Typescript, and CucumberJs and generating reports for m ...

CreateAsyncModule using an import statement from a variable

When trying to load a component using defineAsyncComponent, the component name that should be rendered is retrieved from the backend. I have created a function specifically for loading the component. const defineAsyncComponentByName = (componentName: strin ...

Puppeteer: What is the best way to interact with a button that has a specific label?

When trying to click on a button with a specific label, I use the following code: const button = await this.page.$$eval('button', (elms: Element[], label: string) => { const el: Element = elms.find((el: Element) => el.textContent === l ...

Discover the steps to dynamically set global data in Vue during runtime

I am currently working on a Vue application that requires fetching data from JSP at runtime, which means I cannot use .env files. As a solution, I am attempting to set data in Vue that can be accessed throughout the entire application (components, mixins, ...

A guide to creating a TypeScript redux middleware class

As specified in the typescript definition for Redux, these interfaces must be implemented to create middleware: /* middleware */ export interface MiddlewareAPI<D extends Dispatch = Dispatch, S = any> { dispatch: D getState(): S } /** * A midd ...

Implementing Firebase-triggered Push Notifications

Right now, I am working on an app that is built using IONIC 2 and Firebase. In my app, there is a main collection and I am curious to know if it’s doable to send push notifications to all users whenever a new item is added to the Firebase collection. I ...

Issue with validating the date picker when updating user information

Trying to manage user accounts through a dialog form for adding and updating operations, where the type of operation is determined by a variable injected from the main component. Encountered an issue while launching the update process - the date picker tri ...

Brand new Angular 9 application encountering the error message "ERROR in Cannot read property 'flags' of undefined" when running "ng build" on a Mac device

I set up a fresh Angular 9 project on my MacBook by executing ng new demo (no routing, CSS) cd demo ng build However, I encountered the following error: ERROR in Cannot read property 'flags' of undefined When running "ng version", here's ...

When trying to access the "form" property of a form ElementRef, TypeScript throws an error

I've encountered an issue with accessing the validity of a form in my template: <form #heroForm="ngForm" (ngSubmit)="onSubmit()"> After adding it as a ViewChild in the controller: @ViewChild('heroForm') heroForm: ElementRef; Trying ...

Unable to set up enzyme adapter

Currently, I am in the process of setting up the enzyme adapter for testing purposes. The code snippet that I have is quite straightforward: import * as enzyme from 'enzyme'; import * as Adapter from 'enzyme-adapter-react-16'; enzyme. ...

How to make an optional prop with a default value non-nullable in a ts+react component?

Is there a way to modify a React component to accept an optional prop and then treat it as non-null within the component itself? For example, consider the following basic component: import React from 'react'; type props = { x?: number; }; c ...

Selecting keys of an object in Angular 2

Attempting to fetch data from an API using key selection but encountering retrieval issues. File: app/app.component.ts import {Component, OnInit} from 'angular2/core'; import {Http} from 'angular2/http'; import {httpServiceClass} fro ...

Executing a function in the view/template with Angular 2+

Whenever a function is called in the view of an Angular component, it seems to be executed repeatedly. A typical example of this scenario can be seen below: nightclub.component.ts import { Component } from '@angular/core'; @Component({ selec ...

Verifying the legitimacy of the elements in an n-dimensional array

In my journey to create my own Tensor class (n-dimensional arrays) in typescript, I have devised a structure where the data is stored in a 1D array property, and the shape of the data is stored separately for indexing purposes. My goal is to develop a fun ...