TypeScript 运行时错误:无法读取未定义的属性(枚举)。

61

我有一个名为RESTConfig.ts的文件,其中包含以下界面和枚举:

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

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

我想在另一个类中导入和使用枚举类型,代码如下:

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

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

   }
   ...
}

代码经过Linting和转译后运行正常,但运行时出现以下错误:

TypeError: Cannot read property 'POST' of undefined

错误发生在"method: RESTMethod.POST"这一行。

请问我做错了什么?


找到答案了吗? - VahidNaderi
1
使枚举不再是常量 - 移除 'const' 术语 - John Dow
7个回答

130

我刚刚通过困难的方式发现,如果存在循环导入的话,这种情况也可能发生。


5
这是咬我的东西。 - Esteban
似乎这并不难发生! - Ahmad
这应该进一步向上。 - glinda93
2
我相信这是TypeScript/issues/3200 - davetapley

44

在TypeScript中有两种枚举类型:

  • 经典enum

在TS转换成JS时会转换成真实对象,因此它们存在于运行时。

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(你正在使用的):

在 JavaScript 的转译过程中,常量枚举会被移除,因此你不能在运行时使用它们。根据TS文档,常量枚举的存在是为了“避免支付额外生成的代码和访问枚举值时的额外间接成本”。

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.
所以只需将您的const enum更改为enum,您的运行时错误就会消失。

23
当你使用export declare enum时,也会出现这种情况。 - Michał Tatarynowicz
12
如果需要“导出”枚举并在运行时使用它,您该如何解决这个问题? - Cody

13

这解决了我的错误。 - thelearner

6

当我把枚举放到一个独立的文件中时,它对我有效。


2
可能你有一个循环依赖。 - Wojtek Jureczka

2
如果您在运行测试时遇到此问题,请确保包含具有enum的文件在tsconfig.spec.json文件中。
例如,当枚举位于types.ts文件中时。
{
  [...]
  "include": ["types.ts"]
  [...]
}

0

如果在tsconfig.json中有--isolatedModules或者在ts-loader中有transpileOnly,那你可能会遇到this issue。基本上,你不能将这些与export const enum结合使用。

就像其中一位评论者所说:

transpileOnly意味着逐个转译每个文件...当编译器查看一个文件时,它无法知道它正在查看的引用是否是一个常量枚举,因为声明在另一个文件中并且它无法访问..

所以我认为你不能将这两个概念混合在一起,const enum(需要整个程序的信息)和transpileOnly(逐个文件处理)。


0

试试这个

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

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

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

   }
   ...
}


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接