【问题标题】:Enum inside class (TypeScript definition file)类内的枚举(TypeScript 定义文件)
【发布时间】:2015-07-02 21:48:19
【问题描述】:

我四处搜索,但似乎无法找到答案,希望您能提供帮助。

如何将枚举添加到Image?这是我最理想的情况,但我得到了一个错误。

declare module 'Lib' {
  export module Graphics {
    export class Image {
      enum State {}

      static STATE_IDLE: State;
      static STATE_LOADING: State;
      static STATE_READY: State;
      static STATE_ERROR: State;
      constructor();
    }
  }
}

如果我将State 移动到Graphics 模块中,它可以工作,但现在State 属于Graphics,这是不正确的。它必须是Image 的一部分。

【问题讨论】:

    标签: typescript definition


    【解决方案1】:

    我不确定你打算做什么,但我希望你会想要一个 enum 来表示可能的状态值,然后在图像上使用一个 state 成员来指示当前状态图片。

    declare module 'Lib' {
        export module Graphics {
    
            enum State {
                STATE_IDLE,
                STATE_LOADING,
                STATE_READY,
                STATE_ERROR
            }
    
            export class Image {
                public state: State;
    
                constructor();
            }
    
        }
    }
    

    听起来您想声明一个具有类枚举成员的类,而不是在类中声明一个枚举。即:

    declare module 'Lib' {
    
        export module Graphics {
    
            export class Image {
                static STATE_IDLE: number;
                static STATE_LOADING: number;
                static STATE_READY: number;
                static STATE_ERROR: number;
    
                constructor();
            }
        }
    }
    

    【讨论】:

    • 感谢史蒂夫的回复。我访问任何状态值的方式都是这样的; Lib.Graphics.Image.STATE_READY 而不是公共财产——不是我的决定,但图书馆就是这样。有没有办法在类上做静态枚举?
    • 在这种情况下,我认为您只想在 Image 类上声明类似枚举的成员(这将是 number 类型,就像枚举在引擎盖下一样)。跨度>
    • 我明白了。虽然我有一个只应该接受空闲、加载、就绪或错误的函数——如果它不是其中之一,那么它不应该被允许。如果我将它们声明为数字,人们可以发送“100”,这将是有效的吗?
    【解决方案2】:

    您可以创建具有相同名称的模块和类。重命名您的枚举也可能会有所帮助,这样您就不必说两次State

    declare module 'Lib' {
        export module Graphics {
            export class Image {
                constructor();
            }
    
            export module Image {
                export enum State {
                    Idle,
                    Loading,
                    Ready,
                    Error
                }
            }
        }
    }
    

    【讨论】:

    • 这有点用,但这意味着我必须写“Lib.Graphics.Image.State.STATE_IDLE”而不是“Lib.Graphics.Image.STATE_IDLE”
    • @LewisPeel 那么您要查找的不是类中的枚举,而是类中的静态数字属性。使用史蒂夫的答案,但明确地给每个属性一个值......例如。 static STATE_IDLE: number = 0; static STATE_LOADING: number = 1; 等等...
    • 我认为这是我唯一的选择。很遗憾,因为就像我说的那样,您可以使用 100 而不是 Image.STATE_LOADING 并且编译器不会标记它......但是当代码运行时它会抛出一个错误。
    • 哦,我忘了这是一个定义文件。您不能将值分配给这些成员,但只需确保您在相应的 javascript 文件中执行此操作(我最初的意思是说成员而不是属性)
    【解决方案3】:

    我想我可能已经找到了解决方案……我不知道它是否是有效的 TypeScript,但它可以工作并且不会导致任何编译错误。是以上答案的组合。

    declare module 'Lib' {
    
      module Graphics {
    
        module Image {
          enum State { }
          var STATE_IDLE: State;
          var STATE_LOADING: State;
          var STATE_READY: State;
          var STATE_ERROR: State;
        }
    
        class Image {
          constructor();
        }
    
      }
    
    }
    

    谁能发现我没有注意到的任何潜在问题?

    【讨论】:

    • 我什至可以从枚举内部删除值而不影响任何东西。
    • 现在您可以通过两种方式访问​​它:Image.State.STATE_IDLEImage.STATE_IDLE。看到你的定义的人很难弄清楚他们应该使用什么。
    • 是的。我已经编辑了答案并从枚举内部删除了值......这更有意义。这实际上看起来像 threejs 在他们的定义文件中的内容。
    【解决方案4】:

    我最近也遇到了这个问题。 这是我目前使用的解决方案:

    // File: Image.ts
    
    class Image
    {
        constructor()
        {
            this.state = Image.State.Idle;
        }
    
        state: Image.State;
    }
    
    module Image
    {
        export enum State
        {
            Idle,
            Loading,
            Ready,
            Error
        }
    }
    
    export = Image;
    

    然后在我使用类及其枚举的地方:

    import Image = require("Image");
    
    let state = Image.State.Idle;
    let image = new Image();
    state = image.state;
    

    这似乎工作正常(尽管我不认为这是做这种事情的预期方式)。

    希望 TypeScript 中会有这样的方式:

    class Image
    {
        enum State
        {
            Idle,
            Loading,
            Ready,
            Error
        }
    
        constructor()
        {
            this.state = State.Idle;
        }
    
        state: State;
    }
    
    export = Image;
    

    【讨论】:

      【解决方案5】:

      我认为这种带有模块增强的东西是一种非常笨拙且不直观的做事方式*,所以考虑一下:

      export module Graphics
      {
          enum State
          {
              STATE_IDLE,
              STATE_LOADING,
              STATE_READY,
              STATE_ERROR
          }
      
          export class Image
          {
              constructor() { }
              public static readonly State = State;
          }
      }
      
      //...
      
      let imgState = Graphics.Image.State.STATE_ERROR;
      

      即只在你想添加的类的作用域内声明枚举而不导出它,然后通过类的成员将其暴露出来。

      * 就代码的结构和组织而言,这很糟糕,即使它在技术上可行。

      更新

      declare module Lib
      {
          enum State
          {
              STATE_IDLE,
              STATE_LOADING,
              STATE_READY,
              STATE_ERROR
          }
      
          class ImageClass
          {
              constructor();
              public Prop: any;
          }
      
          export interface Graphics
          {
              Image: typeof State & ImageClass & (new () => typeof State & ImageClass);
          }
      }
      
      declare var Graphics: Lib.Graphics;
      

      然后你输入如下:

      var someEnum = Graphics.Image.STATE_ERROR;
      var image = new Graphics.Image();
      var anotherEnum = image.STATE_IDLE;
      

      【讨论】:

      • 我很感激,但我试图为现有库编写声明,这是我无法控制的,所以“Graphics.Image.State.STATE_ERROR”对我不起作用 - 它必须是'Graphics.Image.STATE_ERROR'
      • @LewisPeel 啊,对不起。我已经更新了答案,这会给您带来任何价值吗?
      【解决方案6】:

      我认为以下是对 KoenT 解决方案的改进:

      export class Image
      {
          constructor ()
          {
              this.state = Image.State.Idle;
          }
      
          state: Image.State;
      }
      
      export namespace Image
      {
          export enum State
          {
              Idle,
              Loading,
              Ready,
              Error
          }
      }
      

      优势在于您可以利用命名导入:

      import {Image} from './image';
      let img = new Image()
      img.state = Image.State.Error
      

      【讨论】:

      • 这个技术也在Declaration Merging下的官方参考中有所描述。要将此技术与export default 一起使用,可以从classnamespace 中删除export 关键字,并在namespace 的右括号之后添加行export default Image;
      • 感谢您的回答!我还不知道这个宣言合并了……哇,太强大了!
      • 它不再工作了。错误:不允许使用“命名空间”和“模块”(无命名空间)。检查typescriptlang.org/docs/handbook/…
      • @Shadoweb 这绝对仍然有效......“no-namespace”错误是 ts-lint 配置(也是一个有争议的配置),而不是打字稿错误。见palantir.github.io/tslint/rules/no-namespacegithub.com/microsoft/TypeScript/issues/30994
      • 不工作,你不能在类本身中使用枚举,真是个负担......
      【解决方案7】:

      这是我的解决方案。

      program.ts:

      enum Status {
          Deleting,
          Editing,
          Existing,
          New
      }
      
      export class Program {
          static readonly Status = Status;
          readonly Status = Program.Status;
      
          title: string;
      
          status: Status;
      
          constructor(init?: Partial<Program>) {
              Object.assign(this, init);
          }
      }
      

      用法:

      let program = new Program({ title: `some title` });
      
      program.status = Program.Status.New;
      

      program.status = program.Status.New;
      

      Angular 2+ 用户的额外好处:这可以在模板中使用

      <div *ngIf="program.status === program.Status.New">
        Only display if status of the program is New
      </div>
      

      【讨论】:

      • 不错的方法但是如果我需要声明一个枚举类型的变量怎么办? enumVar: Program.Status; 不工作
      • 这应该是公认的解决方案,其他的会产生 lint 警告 (github.com/bradzacher/eslint-plugin-typescript/blob/master/docs/…)
      • 不适用于 Angular,除非您删除 static,因为模板不能使用其组件的静态属性。
      • 因此readonly Status = Program.Status; 就在static 之下。
      猜你喜欢
      • 2021-06-14
      • 1970-01-01
      • 2021-01-24
      • 1970-01-01
      • 2015-06-05
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-03-10
      相关资源
      最近更新 更多