Kip
Kip

Reputation: 109503

Typescript enum as a parameter type allows invalid values

In TypeScript, I'm defining an enum, then I want a function to take a parameter whose value is one of the enum's values. However, TypeScript doesn't seem to do any validation on the value, and allows values outside of the enum. Is there a way to do this?

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 enum I can get something similar to what I'm looking for, but I lose some of the functionality of enum.

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'

Upvotes: 8

Views: 2504

Answers (1)

Odinn
Odinn

Reputation: 808

you might be expecting too much from enum in TS... :)

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

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

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

If you run this code above, you will see that all the lines print number that means that behind the scenes it is translated to a number and that's why it accepts everything... Enums are usually just a good practice to avoid magic numbers and make the code more readable

On the other hand, if you stop using numeric enums and actually change the values for A and B to strings you will get:

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)

So what I'm trying to say is that if it's a numeric enum it's just cosmetics and it's treated as a number but if you make a string enum for example then it's actually tries to match the type

Upvotes: 1

Related Questions