Aufzählung innerhalb der Klasse (TypeScript-Definitionsdatei)

78

Ich habe mich umgesehen, kann aber anscheinend keine Antwort darauf finden. Hoffentlich können Sie helfen. Wie kann ich Image eine Aufzählung hinzufügen? Dies ist, was ich idealerweise möchte, aber ich bekomme eine Fehlermeldung.

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();

    }

  }

}

Wenn ich State in das Grafikmodul verschiebe, funktioniert es, aber jetzt gehört State zu Graphics ... was falsch ist, muss es Teil von Image sein.

Irgendwelche Ideen? Vielen Dank

Lewis Peel
quelle

Antworten:

59

Ich denke, das Folgende ist eine Verbesserung der KoenT-Lösung:

export class Image
{
    constructor ()
    {
        this.state = Image.State.Idle;
    }

    state: Image.State;
}

export namespace Image
{
    export enum State
    {
        Idle,
        Loading,
        Ready,
        Error
    }
}

Der Vorteil ist, dass Sie benannte Importe nutzen können:

import {Image} from './image';
let img = new Image()
img.state = Image.State.Error
NSjonas
quelle
4
Diese Technik wird auch in der offiziellen Referenz unter Zusammenführen der Erklärung beschrieben . Um diese Technik mit zu verwenden export default, würde man das exportSchlüsselwort aus classund entfernen namespaceund die Zeile export default Image;nach der schließenden Klammer von hinzufügen namespace.
Zett42
Danke für diese Antwort! Ich wusste noch nicht, dass diese Erklärung verschmilzt und ... wow, das ist mächtig!
Janis Jansen
Es funktioniert nicht mehr. Fehler: 'Namespace' und 'Modul' sind nicht zulässig (kein Namespace). Prüfen typescriptlang.org/docs/handbook/...
Shadoweb
@ Shadoweb das funktioniert definitiv immer noch ... Der Fehler "kein Namespace" ist eine ts-lint-Konfiguration (und eine kontroverse), kein Typoskriptfehler. Siehe palantir.github.io/tslint/rules/no-namespace und github.com/microsoft/TypeScript/issues/30994
NSjonas
funktioniert nicht, Sie können die Aufzählungen in der Klasse selbst nicht verwenden, was für eine Ladung von ...
phil123456
39

Hier ist meine Lösung.

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);
    }
}

Verwendung:

let program = new Program({ title: `some title` });

program.status = Program.Status.New;

oder

program.status = program.Status.New;

Zusätzlicher Vorteil für Angular 2+ -Benutzer: Dies kann in Vorlagen verwendet werden

<div *ngIf="program.status === program.Status.New">
  Only display if status of the program is New
</div>
Mažvydas Tadaravičius
quelle
2
Netter Ansatz, aber was ist, wenn ich eine Variable vom Typ enum deklarieren muss? enumVar: Program.Status;funktioniert nicht
Dimanoid
1
Dies sollte die akzeptierte Lösung sein, die anderen produzieren
Flusenwarnungen
Funktioniert nicht mit Angular, es sei denn, Sie entfernen die, staticda Vorlagen keine statischen Eigenschaften ihrer Komponente verwenden können.
Hutch Moore
Daher readonly Status = Program.Status;knapp darunter static.
Mažvydas Tadaravičius
38

Ich bin kürzlich auch auf dieses Problem gestoßen. Folgendes verwende ich derzeit als Lösung:

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

Dann an der Stelle, an der ich die Klasse und ihre Aufzählung verwende:

import Image = require("Image");

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

Dies scheint gut zu funktionieren (obwohl ich es nicht als den erwarteten Weg betrachte, so etwas zu tun).

Hoffentlich gibt es in TypeScript eine Möglichkeit, dies folgendermaßen zu tun:

class Image
{
    enum State
    {
        Idle,
        Loading,
        Ready,
        Error
    }

    constructor()
    {
        this.state = State.Idle;
    }

    state: State;
}

export = Image;
KoenT
quelle
3

Ich denke, dass dieses Zeug mit Modulerweiterung eine sehr hackige und nicht intuitive * Art ist, Dinge zu tun, also bedenken Sie Folgendes:

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;

Das heißt, deklarieren Sie einfach die Aufzählung im Bereich der Klasse, zu der Sie sie hinzufügen möchten, ohne sie zu exportieren, und machen Sie sie dann über ein Mitglied der Klasse verfügbar.

* Was in Bezug auf Strukturierung und Organisation von Code schlecht ist, auch wenn es technisch funktioniert.

Aktualisieren

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;

Dann tippen Sie wie folgt:

var someEnum = Graphics.Image.STATE_ERROR;
var image = new Graphics.Image();
var anotherEnum = image.STATE_IDLE;
Alex
quelle
Ich weiß das zu schätzen, aber ich habe versucht, eine Deklaration für eine vorhandene Bibliothek zu schreiben, die außerhalb meiner Kontrolle liegt, sodass 'Graphics.Image.State.STATE_ERROR' für mich nicht funktioniert - es muss 'Graphics.Image.STATE_ERROR' sein
Lewis Peel
@ LewisPeel Ah, sorry. Ich habe die Antwort aktualisiert. Würde Ihnen das irgendeinen Wert geben?
Alex
2

Ich glaube, ich habe vielleicht eine Lösung gefunden ... ob es sich um gültiges TypeScript handelt, weiß ich nicht, aber es funktioniert und verursacht keine Kompilierungsfehler. Es ist eine Kombination der obigen Antworten.

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();
    }

  }

}

Kann jemand mögliche Probleme damit erkennen, die ich nicht bemerkt habe?

Lewis Peel
quelle
Ich könnte wahrscheinlich sogar die Werte aus den Aufzählungen entfernen, ohne irgendetwas zu beeinflussen.
Lewis Peel
Jetzt können Sie auf zwei Arten darauf zugreifen: Image.State.STATE_IDLEund Image.STATE_IDLE. Es ist ein wenig schwierig für jemanden, der sich Ihre Definition ansieht, herauszufinden, was er verwenden soll.
David Sherret
Wahr. Ich habe die Antwort bearbeitet und die Werte aus der Aufzählung entfernt ... was sinnvoller ist. Dies sieht tatsächlich so aus, wie es threejs in seiner Definitionsdatei hat.
Lewis Peel
1

Ich bin mir nicht sicher, was Sie vorhaben, aber ich hätte erwartet, dass Sie enumdie möglichen Statuswerte darstellen und dann ein stateMitglied auf dem Bild, um den aktuellen Status des Bildes anzuzeigen.

declare module 'Lib' {
    export module Graphics {

        enum State {
            STATE_IDLE,
            STATE_LOADING,
            STATE_READY,
            STATE_ERROR
        }

        export class Image {
            public state: State;

            constructor();
        }

    }
}

Es hört sich so an, als ob Sie eine Klasse mit enumähnlichen Mitgliedern deklarieren möchten, anstatt eine Enumeration innerhalb einer Klasse zu deklarieren. dh:

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();
        }
    }
}
Fenton
quelle
Danke für deine Antwort Steve. Die Art und Weise, wie ich auf einen der Statuswerte zugreife, ist wie folgt. Lib.Graphics.Image.STATE_READY statt eines öffentlichen Eigentums - nicht meine Entscheidung, aber so ist die Bibliothek. Gibt es eine Möglichkeit, statische Aufzählungen für Klassen durchzuführen?
Lewis Peel
In diesem Fall möchten Sie meiner Meinung nach nur die enumähnlichen Mitglieder der ImageKlasse deklarieren (dies sind numberTypen, genau wie Enums unter der Haube sind).
Fenton
Aha. Obwohl ich eine Funktion habe, die nur Leerlauf, Laden, Bereit oder Fehler akzeptieren sollte - wenn es keine davon ist, sollte es nicht erlaubt sein. Wenn ich sie als Zahlen deklarieren lassen würde, könnten die Leute "100" senden und es wäre gültig, oder?
Lewis Peel
0

Sie können ein Modul und eine Klasse mit demselben Namen erstellen. Es kann auch hilfreich sein, Ihre Aufzählung umzubenennen, damit Sie nicht Statezweimal sagen müssen :

declare module 'Lib' {
    export module Graphics {
        export class Image {
            constructor();
        }

        export module Image {
            export enum State {
                Idle,
                Loading,
                Ready,
                Error
            }
        }
    }
}
David Sherret
quelle
Gleiches gilt für das Erstellen einer Klasse innerhalb einer Klasse .
David Sherret
Das funktioniert irgendwie, aber es bedeutet, dass ich "Lib.Graphics.Image.State.STATE_IDLE" anstelle von "Lib.Graphics.Image.STATE_IDLE" schreiben muss
Lewis Peel
2
@LewisPeel dann suchen Sie nicht nach einer Aufzählung in einer Klasse, sondern nach statischen Zahleneigenschaften in einer Klasse. Verwenden Sie Steves Antwort, aber geben Sie jeder dieser Eigenschaften explizit einen Wert ... z. static STATE_IDLE: number = 0; static STATE_LOADING: number = 1;etc ...
David Sherret
Ich denke, das ist meine einzige Option. Es ist allerdings eine Schande, denn wie gesagt, Sie könnten 100 anstelle von Image.STATE_LOADING verwenden, und der Compiler würde es nicht anzeigen ... aber wenn der Code ausgeführt wird, wird ein Fehler ausgegeben.
Lewis Peel
Oh, ich habe vergessen, dass dies eine Definitionsdatei war. Sie können diesen Mitgliedern keine Werte zuweisen, aber stellen Sie sicher, dass Sie dies in der entsprechenden Javascript-Datei tun (ich wollte ursprünglich Mitglieder und nicht auch Eigenschaften sagen)
David Sherret