Utilizing Union type and static declarations instead of String Enum

In my opinion, the following approach works better in TypeScript compared to using Enums. I am looking for a way to simplify this process, perhaps by using a utility type. It would be ideal if we could define Enums to function in a similar way, but unfortunately, that doesn't seem to be possible as far as I know.

Current code explanation:

StepWizardEventType restricts the possible values for an event type, and the const is utilized to access these values in the code. The type of the const

{ [prop: string]: StepWizardEventType }
allows variables/properties to be of type StepWizardEventType and assigned one of the values from the const stepWizardEventTypes.

export type StepWizardEventType = 'cancel' | 'create' | 'init' | 'next' | 'previous' | 'reset' | 'save';

export const stepWizardEventTypes: { [Property in StepWizardEventType]: StepWizardEventType } = {
  cancel: 'cancel',
  create: 'create',
  init: 'init',
  next: 'next',
  previous: 'previous',
  reset: 'reset',
  save: 'save',
};

export interface StepEvent {
  type: StepWizardEventType;
}

// somewhere else in another file...

const event: StepEvent = {
  type: stepWizardEventTypes.cancel // compiler doesn't complain here! yay!
}

EDIT: The compiler raises issues with the example enum usage.

export enum EventTypes {
  cancel = 'cancel',
  create = 'create'
}

type EventType = 'cancel' | 'create';

interface Dodad {
  eventType: EventType;
}

const doDadInstance: Dodad = {
  eventType: EventTypes.cancel // TypeScript complains here for enums
}

Answer №1

After receiving feedback from @jcalz, I have made some improvements to this code. Although I believe there is still room for simplification, it is now in better shape.

type enumPropertyKey = { readonly [P in string]: P };

const createEnumFromKeys = <K extends string>(...keys: K[]): enumPropertyKey => Object.fromEntries(
    keys.map(key => [key, key])
) as enumPropertyKey;

// Example of how to use the function

const actionTypes = createEnumFromKeys('cancel', 'create', 'init', 'next', 'previous', 'reset', 'save');
type ActionType = keyof typeof actionTypes;

export interface StepEvent {
    type: ActionType;
}

// In another file...

const event: StepEvent = {
    type: actionTypes.cancel
}

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

Template specific requirements in Angular

When I have a child component app-page-header, here's what I want to achieve: If the value of headerOptions.headerTitle is not 'Idle Disposition', then set [titleData] to equal 'headerOptions.headerTitle'. However, if headerOptions ...

Utilizing NgModelGroup nesting in various components for improved data management

Whenever I attempt to nest NgModelGroup inside another NgModelGroup, Angular seems to just ignore it. I'm currently utilizing Angular 12 and Template-driven Forms. Here is how my code appears: app.component.html <form #form="ngForm"> ...

The compiler is showing an error with code TS5023, indicating that the option 'strictTemplates' is not recognized

When trying to compile my Angular application (v10), I encountered the following error message. An unexpected issue has occurred: tsconfig.json:14:5 - error TS5023: Unknown compiler option 'strictTemplates'. 14 "strictTemplates": t ...

"Exploring the power of Angular 16 coupled with Firebase 9 for seamless file

Recently, I've been facing some challenges with my Angular 16 app that uses Firebase 9 and angular/fire 7. Specifically, I've been struggling to implement a simple file upload feature to Firebase storage. Despite spending the last couple of days ...

"Learn the process of extracting information from a database and exporting it to a CSV file with Angular 2

Currently, I am facing an issue where I need to retrieve data from a database and export it to a CSV file. While I am able to fetch all the data successfully, I am encountering difficulty when trying to fetch data that is in object format as it shows up as ...

Interface definition triggers an error when assigning a string literal to a field

When defining a string literal type in an interface, I encountered unexpected behaviors. interface IFoo { value: 'foo' | 'boo'; } Upon implementation of the interface in a class, I encountered an error: class Foo implements IFoo ...

acquiring the main class instance within a function without relying on an arrow function

Within my Angular project, I have integrated a datatable with row grouping and row callbacks. Datatable Options openPositionDatatableOptions = { sDom: 'rt<"bottom"p>', ajax: (data, callback, settings) => { this.service.ge ...

What causes an interface to lose its characteristics when a property is defined using index signatures?

Here's the code snippet I'm having trouble with, which involves tRPC and Zod. import { initTRPC, inferRouterOutputs } from '@trpc/server'; import { z } from "zod"; const t = initTRPC.create(); const { router, procedure } = t; ...

The request to search for "aq" on localhost at port 8100 using Ionic 2 resulted in a 404 error, indicating that the

Trying to create a basic app that utilizes an http request, but facing challenges with cors in ionic 2. To begin with, modifications were made to the ionic.config.json { "name": "weatherapp", "app_id": "", "v2": true, "typescript": true, "prox ...

Disable inline imports when implementing an interface in vscode by selecting the "Implement interface" option

When using TypeScript, if I perform an auto-fix on a class name by selecting "Implement interface", it will generate the methods with inline imports like this: getInbox(): Observable<import('../../model/Message').Interactions[]> { t ...

Finding the row index in an Angular material table

How can I retrieve the row index in an Angular material table? <td mat-cell *matCellDef="let row"> <mat-checkbox (click)="$event.stopPropagation()&quo ...

Oops! It appears that there is an issue with the 'value' property in Vue3

I encountered an issue while trying to reference a state variable through the store mechanism import { AppState } from '@/types' import { localStorage } from '@/utils/storage'; import { defineStore } from 'pinia'; import { get ...

Angular is showing an error stating that the type 'EventEmitter' is not generic

As I follow along with a tutorial, I've come across the use of EventEmitter. The code snippet provided in the tutorial is as follows: @Output() ratingClicked: EventEmitter<string> = new EventEmitter<string>(); However, my Visual ...

Conflicting TypeScript errors arise from a clash between React version 16.14 and @types/hoist-non-react-statics 3.3.1

Currently in the process of upgrading an older project to React 16.14, as we are not yet prepared for the potential breaking changes that would come with moving up to React 17 or 18. As part of this upgrade, I am also updating redux and react-redux to ver ...

Callback after completion of a for loop in Angular TypeScript

During the execution of my javascript async function, I encountered a situation where my printing code was running before the div creation. I needed to ensure that my print code would run only after the completion of the for loop, but I struggled to find a ...

Encountering an error in Chrome where the property 'command' is undefined

Currently utilizing typescript and encountered an error in the chrome console: Error found in event handler for (unknown): TypeError: Unable to access property 'command' as it is undefined at chrome-extension://somethingsomethingsometh ...

Merging two arrays in Typescript and incrementing the quantity if they share the same identifier

I am currently working on my Angular 8 project and I am facing a challenge with merging two arrays into one while also increasing the quantity if they share the same value in the object. Despite several attempts, I have not been able to achieve the desired ...

Avoiding an endless spiral on a setter in JavaScript/TypeScript

Implementing TypeScript, I've been working on setting up a concept called a "trigger" : an object that includes both a checker function (which returns a Boolean) and a behavior function capable of performing various tasks. My aim is to execute the che ...

The element does not have a property named 'className' in the object type '{ props: ReactNode; }'

I am currently in the process of converting a Next.js project from JavaScript to TypeScript, and I encountered an issue: Property 'className' does not exist on type '{ props: ReactNode; }'. In JavaScript, I could access className from p ...

Setting up ReactJS and TypeScript in a fresh MVC5 project from scratch

After extensively trying out various tutorials, I have yet to successfully run a basic MVC5 project using TypeScript and ReactJS. For reference, I have created these projects from scratch in Visual Studio 2015 with .NET 4.6.1, using the ASP.NET Web Applic ...