Restricting certain enums in Typescript

Apologies in advance if this question has been asked before, but I am struggling to phrase it in a way that leads me to a solution.

I have an enum type:

enum Events {
 FOO = 'foo',
 BAR = 'bar'
}

There is a function that accepts another function as a parameter. The function it accepts has a type EventHandler

export const wrapEventFn = async (fn: EventHandler): Promise<unknown> => {
...

The type definition for EventHandler is:

type EventHandler = (event: Events) => Promise<void>

Now, the functions that I pass are restricted to handling specific events. For example:

export const actionHandler = async (
  event: Events.FOO
): Promise<void> => {...

However, when trying to use the above code, TypeScript throws an error:

wrapEventFn(actionHandler) // actionHandler is underlined w error 

Error

Argument of type '(event: Events.FOO) => Promise<void>' is not assignable to parameter of type 'EventHandler'.
  Types of parameters 'event' and 'event' are incompatible.
    Type 'Events' is not assignable to type 

How can I resolve this issue?

Playground

Answer №1

Instead of using the enum keyword, it is recommended to utilize String Literal Types

type Events = 'foo' | 'bar'

Modify EventHandler to accept a generic object that can be assigned with type Events:

type EventHandler<T extends Events> = (event: T) => Promise<void>;

declare function wrapEventFn<T extends Events>(fn: EventHandler<T>): Promise<unknown>;

We can now create a specialized type which includes only certain events:

type SpecializedEvents = 'foo'; 
declare function actionHandler(event: SpecializedEvents): Promise<void>;

The implementation to call this will look like:

wrapEventFn<SpecializedEvents>(actionHandler);

In fact, specifying the generic type is not necessary as TypeScript compiler can deduce it automatically. Therefore, it is clearer to write simply:

wrapEventFn(actionHandler);

To demonstrate the functionality, let's try passing an incompatible type:

type CompletelyTheWrongType = 'this' | 'is' | 'wrong';
declare function wrongActionHandler(event: CompletelyTheWrongType): Promise<void>;

wrapEventFn(wrongActionHandler);

Above code would produce the following error message:

Arguments of type '(event: CompletelyTheWrongType) => Promise' is not assignable to parameter of type 'EventHandler'...

playground 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

A guide on effectively utilizing BehaviorSubject for removing items from an array

Currently, I am working on an Angular 8 application that consists of two components with a child-parent relationship. It came to my notice that even after removing an item from the child component, the item remains visible in the parent component's li ...

Press the key to navigate to a different page

I have an input field for a search box. I want it so that when I enter my search query and press enter, the page navigates to another page with the value of the input included in the URL as a query string. How can I achieve this functionality? Thank you ...

Tips for verifying the variable type in a TypeScript ESLint custom rule

Trying my hand at creating a custom TypeScript-eslint rule that requires the callee's object of a node to be of a specific type, which I'll refer to as MyType. Utilizing the CallExpression from typescript-eslint in the code snippet below: Source ...

Unable to utilize class identifiers in TypeScript because of 'incompatible call signatures' restriction

Following the execution of relevant yarn add commands, the following lines were added to the packages.json: "@types/classnames": "^2.2.7", "classnames": "^2.2.6", Subsequently, I incorporated these lines into my typescript files: import * as classnames ...

Passing properties from the parent component to the child component in Vue3JS using TypeScript

Today marks my inaugural experience with VueJS, as we delve into a class project utilizing TypeScript. The task at hand is to transfer the attributes of the tabsData variable from the parent component (the view) to the child (the view component). Allow me ...

Accessing the value of an Observable variable without triggering the assigned function to run again

Currently, I have a function in my Angular component that is executed whenever I need to upload a list of files. I aim to monitor the upload progress to empty the file list and keep track of the upload progress for a progress bar display. The issue I am ...

What is the best way to resolve the unusual resolution issue that arises when switching from Next.js 12 to 13

Previously, I created a website using nextjs 12 and now I am looking to rebuild it entirely with nextjs 13. During the upgrade process, I encountered some strange issues. For example, the index page functions properly on my local build but not on Vercel. ...

Initiate and terminate server using supertest

I've developed a server class that looks like this: import express, { Request, Response } from 'express'; export default class Server { server: any; exp: any; constructor() { this.exp = express(); this.exp.get('/' ...

Encountered Typescript issue when utilizing typed forms in Angular

Below is the interface I am working with: export interface ILoginDto { email: string; password: string; } Here is a snippet of the relevant code from the component: import { FormBuilder, FormGroup, Validators } from '@angular/forms'; export ...

What is the reason behind TypeScript failing to provide type safety in a generic higher order component which introduces extra properties into React components?

I'm currently working on developing a versatile higher order component, but have encountered an issue with type safety not being enforced. Interestingly, when attempting the same implementation without using generics, the type safety is verified as ex ...

What is the subclass of all object literal types in TypeScript?

With the `strictFunctionTypes` setting turned on, function parameters are checked contravariantly. interface Func<T> { (p: T): unknown } declare let b: Func<{p1: string}> declare let c: Func<{p2: number}> declare let d: Func<{p3: nu ...

The subscription functionality within the extended class constructor is not functioning as intended

An abstract class named CoreButtonService has been created, which will serve as the base for other ButtonServices like UserButtonService and MessageButtonService. These services will be injected into corresponding components such as UserComponent and Messa ...

Is Iterating Over Elements Using Angular4/Typescript's ForEach Possible?

While searching for information, I noticed many responses regarding the use of ngFor. However, my question pertains to the angular.forEach() method utilized in my Angular 1 controllers. Unfortunately, these are being identified as errors in TS and fail to ...

How can I change a relative import to absolute in Angular 6?

Is there a way to change relative imports to absolute imports in Angular 6? Here's an example Instead of using ../../../../environments/environment, can we just use environments/environment instead? ...

Async retrieval of values from Ionic storage

I am facing an issue where I need to retrieve two values stored in Ionic storage, but the values are retrieved asynchronously causing the request to happen before the values are fetched. The values for Auth and url are stored in Ionic storage. import { I ...

Error: the attempt to execute the mongoose connection function has failed due to it not being recognized as a valid function

Hey there, I'm encountering the error TypeError: mongoose__WEBPACK_IMPORTED_MODULE_15___default.a.connect is not a function import mongoose from "mongoose"; const dbURI = 'myurlstuffhere'; mongoose.connect(dbURI , {useNewUrlParser: ...

I'm encountering an issue in my node application where it is unable to access the push

I am a beginner in the world of node.js and express. Whenever I try to start my application using the command npm start, I encounter an error message saying Cannot Read property push of undefined from my index.js file. The problematic code snippet looks l ...

The performance of ternary operators in Typescript-based Reactjs fell short of my expectations

As a newcomer to TypeScript+ReactJS, I am facing an issue with the Ternary operator in my code. Here is the code snippet: import React, { SyntheticEvent,useRef,useState } from "react"; import Result from './Result'; //main application c ...

"Enhance your UI development with React using TypeScript as a core

I'm interested in incorporating React Core-UI into my project, but I can't seem to find a React Typescript version. Can anyone provide guidance on how to proceed with this issue? Is there a method for integrating Typescript into the Core-UI proj ...

PostgreSQL reverse relationship

I have a table in my database called "textDate" class TextData extends BaseEntity{ id(primaryGeneratedColumn) ar:string en:string } This entity is used to store all text in my project, such as titles, descriptions, and other fields that have foreign ...