73

I have the following interface and enum in a file RESTConfig.ts:

export const enum RESTMethod {
   POST = "POST",
   GET = "GET"
}

export interface RESTConfig {
   url: string;
   method: RESTMethod;
   data: any;
}

I want to import and use the enum in another class as such:

import { RESTConfig, RESTMethod } from './RESTConfig';

class Pipelines {
   ...
   private someMethod() {
      let rest: RESTConfig = {
         url: "",
         method: RESTMethod.POST,
         data: {}
      }
      ...

   }
   ...
}

Linting and transpiling works fine, but at runtime I get the following error:

TypeError: Cannot read property 'POST' of undefined

on the line "method: RESTMethod.POST".

Can someone tell me what I'm doing wrong?

2
  • Did find the answer? Commented Sep 15, 2018 at 20:23
  • 1
    make the enum not constant - remove 'const' term Commented Sep 19, 2018 at 12:22

6 Answers 6

164

I just found out the hard way that this can also happen if you have circular imports.

Sign up to request clarification or add additional context in comments.

4 Comments

This is what bit me
Seems that is not so hard to happen!
This should go upward further
I believe this is TypeScript/issues/3200
48

In Typescript there are 2 kinds of enums:

  • Classic enum:

During TS to JS transpilation they are converted to real objects, so they exist at runtime.

enum Response {
    No = 0,
    Yes = 1,
}

const yes = Response.Yes; // Works at runtime

const nameOfYes = Response[yes]; // Also works at runtime because a reverse mapping is also generated during transpilation
  • const enum (the one you are using):

Const enums are removed during transpilation in JS so you can not use them at runtime. As per TS doc const enums exists to avoid paying the cost of extra generated code and additional indirection when accessing enum values.

const enum Response {
    No = 0,
    Yes = 1,
}

const yes = Response.Yes; // At runtime: ReferenceError: Response is not defined

const nameOfYes = Response[yes]; // During transpilation: TS2476: A const enum member can only be accessed using a string literal.

So just change your const enum to enum and your runtime error will be gone.

4 Comments

Also happens when you export declare enum.
@MichałTatarynowicz how do you workaround this if you need to export your enum but also need to use it at runtime?
In my case, just removing the export was enough. Not sure what to do when it is required.
export enum worked for me without declare
21

And if you want to identify your circular dependencies, run npx madge --circular --extensions ts ./

(Credit: Andrejs Abrickis's blog https://andrejsabrickis.medium.com/locate-circular-dependencies-in-typescript-modules-2b1eb03dbf2e)

1 Comment

This fixed my error
7

It works for me when put enum into an independent file

1 Comment

Probably you had a circular dependency
2

If you have this issue while running tests make sure that the file with the enum is included in the tsconfig.spec.json file.

e.g. when the enum is in a types.ts file

{
  [...]
  "include": ["types.ts"]
  [...]
}

Comments

0

If you have --isolatedModules in tsconfig.json or transpileOnly in ts-loader, you may be hitting this issue. Basically, you cannot use these things in combination with export const enum.

In the words of a commenter there:

transpileOnly means transpile every file one at a time.. when the compiler is looking at one file, it has no way to know if the reference it is looking at is a const enum or not, since the declaration is in another file that it does not have access to..

so I do not think you can mix these two concepts, const enums (require whole program information), and transpileOnly (one file at a time).

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.