Enum усередині класу (файл визначення TypeScript)


82

Я шукав навколо, але не можу знайти відповіді на це, сподіваюся, ви можете допомогти. Як я можу додати перелік до Зображення? Це те, чого я хотів би в ідеалі, але я отримую помилку.

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, що неправильно. Це має бути частиною Іміджу.

Відповіді:


64

Я думаю, що наступне є вдосконаленням рішення 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

4
Цей метод також описаний в офіційному посиланні під Декларацією злиття . Щоб використати цю техніку з export default, слід видалити exportключове слово з classта namespaceі додати рядок export default Image;після заключної дужки namespace.
zett42

Дякую за цю відповідь! Я ще не знав про злиття цієї Декларації і .. ого, це потужно!
Janis Jansen

Це вже не працює. Помилка: заборонено використання простору імен та модуля (no-namespace). Перевірити typescriptlang.org/docs/handbook / ...
Shadoweb

@Shadoweb це, безумовно, все ще працює ... Помилка "no-namespace" - це конфігурація ts-lint (і суперечлива), а НЕ помилка машинопису. Див palantir.github.io/tslint/rules/no-namespace і github.com/microsoft/TypeScript/issues/30994
NSjonas

1
не працює, ви не можете використовувати перелічення всередині самого класу, яке навантаження ....
phil123456

41

Ось моє рішення.

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>

2
Хороший підхід, але що, якщо мені потрібно оголосити змінну типу enum? enumVar: Program.Status;не працює
Діманоїд

1
Це має бути прийнятим рішенням, інші видають попередження про ворсинки ( github.com/bradzacher/eslint-plugin-typescript/blob/master/docs/… )
graup

Не працює з Angular, якщо ви не видалите, staticоскільки шаблони не можуть використовувати статичні властивості свого компонента.
Хатч Мур

Звідси readonly Status = Program.Status;трохи нижче static.
Mažvydas Tadaravičius

38

Я також нещодавно зіткнувся з цією проблемою. Це те, що я зараз використовую як рішення:

// 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;

3

Я думаю, що ці речі з доповненням модулів - це дуже шалений та неінтуїтивний спосіб * робити щось, тому враховуйте це:

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'
Lewis Peel

@LewisPeel Ах, вибачте. Я оновив відповідь, чи це дасть вам якесь значення?
Олексій

2

Я думаю, що я, можливо, знайшов рішення ... чи дійсний 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_IDLEі Image.STATE_IDLE. Комусь, хто дивиться на ваше визначення, трохи важко зрозуміти, що вони повинні використовувати.
Девід Шеррет,

Правда. Я відредагував відповідь і видалив значення зсередини переліку ... що має більше сенсу. Це насправді схоже на те, що threejs має у своєму файлі визначень.
Льюїс Піл,

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", і це було б дійсним, так?
Льюїс Піл,

0

Ви можете створити модуль і клас з однаковим іменем. Це також може допомогти перейменувати ваш перелік, так що вам не доведеться говорити 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"
Льюїс Піл,

2
@LewisPeel, тоді ви шукаєте не перелік у класі, а властивості статичного числа в класі. Використовуйте відповідь Стіва, але явно надайте кожному з цих властивостей значення ... напр. static STATE_IDLE: number = 0; static STATE_LOADING: number = 1;тощо ...
Девід Шеррет,

Я думаю, що це мій єдиний варіант. Шкода, хоча, як я вже сказав, ви можете використовувати 100 замість Image.STATE_LOADING, і компілятор не буде позначати це ... але коли код запускається, він видасть помилку.
Льюїс Піл,

О, я забув, що це файл визначення. Ви не можете призначити значення цим учасникам, але просто переконайтесь, що ви це зробите у відповідному файлі javascript (я мав на увазі спочатку сказати учасники, а не властивості)
Девід Шеррет,
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.