Using a Typescript enum as a parameter type can lead to accepting incorrect values

When working with TypeScript, I have defined an enum, and now I want to create a function that accepts a parameter whose value is one of the enum's values. However, TypeScript does not validate the value against the enum, allowing values outside of the specified range to be passed. Is there a way to enforce this validation?

Example

enum myenum {
    hello = 1,
    world = 2,
}

const myfunc = (num:myenum):void => console.log(`num=${num}`);

myfunc(1);            // num=1 (expected)
myfunc(myenum.hello); // num=1 (expected)

//THE ISSUE: I'm expecting next line to be a TS compile error, but it is not
myfunc(7); // num=7

Alternative

If I use a type instead of an enum, I can achieve a similar outcome in terms of validation. However, by using a type, I may lose some of the additional functionality provided by enums.

type mytype = 1|2;
const myfunc = (num:mytype):void => console.log(`num=${num}`);

myfunc(1);
myfunc(7);  //TS Compile Error: Argument of type '7' is not assignable to a parameter of type 'mytype'

Answer №1

It seems like you may have high expectations for enums in TypeScript... :)

enum MyCoolEnum {
  A = 1,
  B = 2,
}

function test(data: MyCoolEnum) {
  console.log(`Test = ${typeof data}`)
}

test(1)
test(MyCoolEnum.A)
test(500)

When you run the code above, you'll notice that all lines print number, indicating that it's internally treated as a number and hence accepts any value. Enums are mainly a way to avoid using random numbers and enhance code readability.

However, if you switch from numeric values to string values for A and B, you'll encounter:

TSError: ⨯ Unable to compile TypeScript:
dima.ts:10:6 - error TS2345: Argument of type '1' is not assignable to parameter of type 'MyCoolEnum'.

10 test(1)
        ~
dima.ts:12:6 - error TS2345: Argument of type '500' is not assignable to parameter of type 'MyCoolEnum'.

12 test(500)
        ~~~

    at createTSError (/Users/odinn/.nvm/versions/node/v10.15.1/lib/node_modules/ts-node/src/index.ts:423:12)
    at reportTSError (/Users/odinn/.nvm/versions/node/v10.15.1/lib/node_modules/ts-node/src/index.ts:427:19)
    at getOutput (/Users/odinn/.nvm/versions/node/v10.15.1/lib/node_modules/ts-node/src/index.ts:554:36)
    at Object.compile (/Users/odinn/.nvm/versions/node/v10.15.1/lib/node_modules/ts-node/src/index.ts:760:32)
    at Module.m._compile (/Users/odinn/.nvm/versions/node/v10.15.1/lib/node_modules/ts-node/src/index.ts:839:43)
    at Module._extensions..js (internal/modules/cjs/loader.js:700:10)
    at Object.require.extensions.(anonymous function) [as .ts] (/Users/odinn/.nvm/versions/node/v10.15.1/lib/node_modules/ts-node/src/index.ts:842:12)
    at Module.load (internal/modules/cjs/loader.js:599:32)
    at tryModuleLoad (internal/modules/cjs/loader.js:538:12)
    at Function.Module._load (internal/modules/cjs/loader.js:530:3)

In summary, while numeric enums primarily serve as cosmetic enhancements representing numbers, switching to string enums enforces specific types matching.

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

Cypress: Importing line in commands.ts is triggering errors

After adding imports to the commands.ts file, running tests results in errors. However, in commands.ts: import 'cypress-localstorage-commands'; /* eslint-disable */ declare namespace Cypress { interface Chainable<Subject = any> { c ...

Type error TS2322: You can't assign type 'undefined' to type 'string'

I am currently in the process of creating a chatbot for an upcoming exhibition and encountered the following error: src/app/chat/chat.component.ts:32:9 - error TS2322: Type 'undefined' is not assignable to type 'string'. 32 th ...

Utilizing Jest and nest.js for testing with absolute paths

Looking at my jest configuration inside the package.json: "jest": { "moduleFileExtensions": [ "js", "json", "ts" ], "moduleDirectories":["node_modules", "src" ...

Is there a way to instruct Babel to generate polyfills such as `__createClass` only once for multiple files?

In my project, I have multiple ES6 files, each containing at least one class. For every file, the __createClass, __interopRequireDefault, and __classCallback polyfilling functions are generated. I plan to concatenate them using browserify, but it seems re ...

Using optional chaining with TypeScript types

I'm dealing with a complex data structure that is deeply nested, and I need to reference a type within it. The issue is that this type doesn't have its own unique name or definition. Here's an example: MyQuery['system']['error ...

The test() function in JavaScript alters the output value

I created a simple form validation, and I encountered an issue where the test() method returns true when called initially and false upon subsequent calls without changing the input value. This pattern repeats with alternating true and false results. The H ...

Utilizing an Angular Service within a method, embedded in a class, nested inside a module

module Helper { export class ListController { static handleBatchDelete(data) { // Implementing $http functionality within Angular ... $http.post(data) } } } // Trigger on button click Helper.ListController. ...

Transition from using ReactDOM.render in favor of asynchronous callback to utilize createRoot()

Is there a React 18 equivalent of this code available? How does it handle the asynchronous part? ReactDOM.render(chart, container, async () => { //code that styles some chart cells and adds cells to a worksheet via exceljs }) ...

Difficulty in monitoring the present machine status through XState in a React application

I'm encountering an issue where I am trying to access the Machine state from within a function in a React component using state.value. However, the current state never changes and it always displays the initial state. Strangely, if I include an onClic ...

Is there a way to utilize the 'interval' Rxjs function without triggering the Change Detection routine?

My goal is to display the live server time in my application. To achieve this, I created a component that utilizes the RXJS 'interval' function to update the time every second. However, this approach triggers the Change Detection routine every se ...

Issue encountered while utilizing JQueryUI alongside TypeScript and the definition file from DefinitelyTyped

Currently, I'm attempting to incorporate JQueryUI with TypeScript by first installing JQueryUI using npm install jquery-ui-dist, and then installing JQuery with npm install jquery. Additionally, I have included the definition files from DefinitelyType ...

TypeScript's type casting will fail if one mandatory interface property is missing while an additional property is present

While running tsc locally on an example file named example.ts, I encountered some unexpected behavior. In particular, when I created the object onePropMissing and omitted the property c which is not optional according to the interface definition, I did not ...

Having difficulty creating a TypeScript function

I've encountered a TypeScript error that has left me puzzled: src/helpers.ts:11:14 - error TS2322: There's an issue with this piece of code and I can't quite grasp it: Type '<T extends "horizontal" | "vertical" | undefined, U extends ...

The specified type 'Observable<{}' cannot be assigned to the type 'Observable<HttpEvent<any>>'

After successfully migrating from angular 4 to angular 5, I encountered an error in my interceptor related to token refreshing. The code snippet below showcases how I intercept all requests and handle token refreshing upon receiving a 401 error: import { ...

Declarations of Typescript React for Props for Specific Element

I am trying to specify types for certain elements like <button> or <input>, but I am unable to differentiate between specific element types. Here is an example: interface Props{ component: React.ComponentProps<"button"> | nev ...

`Drizzle ORM and its versatile approach to SELECT statements`

Looking to improve the handling of options in a function that queries a database using Drizzle ORM. Currently, the function accepts options like enabled and limit, with potential for more options in the future. Here's the current implementation: type ...

What is the best way to incorporate sturdy data types into the alternative function for this switch statement

const switchcase = (value, cases, defaultCase) => { const valueString = String(value); const result = Object.keys(cases).includes(valueString) ? cases[valueString] : defaultCase; return typeof result === 'function' ? result() : r ...

Tips for effectively managing loading and partial states during the execution of a GraphQL query with ApolloClient

I am currently developing a backend application that collects data from GraphQL endpoints using ApolloClient: const client = new ApolloClient({ uri: uri, link: new HttpLink({ uri: uri, fetch }), cache: new InMemoryCache({ addTypename: f ...

Steps for integrating custom slot properties in MUI data grids

Custom pagination has been successfully implemented using the mui datagrid component. However, when attempting to pass props for pagination using datagrid's slotProps, an issue arises stating that the type of onChange does not match. How can this be c ...

Discover the Hassle-Free Approach to Triggering Angular Material Menu with ViewChild and MatMenuTrigger

Is there a way to programmatically open an Angular Material menu using a Template Reference Variable on a button trigger that is accessed in the component through ViewChild? I want the menu to open when the mouse hovers over it, instead of just clicking i ...