Navigation

    Logo
    • Register
    • Login
    • Search
    • Recent
    • Tags
    • Unread
    • Categories
    • Unreplied
    • Popular
    • GitHub
    • Docu
    • Hilfe
    1. Home
    2. Deutsch
    3. Skripten / Logik
    4. JavaScript
    5. TypeScript und common.states (Record<string, string>)

    NEWS

    • Neuer Blog: Fotos und Eindrücke aus Solingen

    • ioBroker@Smart Living Forum Solingen, 14.06. - Agenda added

    • ioBroker goes Matter ... Matter Adapter in Stable

    TypeScript und common.states (Record<string, string>)

    This topic has been deleted. Only users with topic management privileges can see it.
    • N
      noox last edited by noox

      Ich habe gesehen, dass common.states (für createState) als Record<string, string> definiert ist: https://github.com/DefinitelyTyped/DefinitelyTyped/blob/master/types/iobroker/index.d.ts

      So ganz happy bin ich mit dem Record nicht, weil man zumindest im einfachsten Fall mit Zeichenketten herum hantiert, wo natürlich schnell mal ein Tippfehler passieren kann. Außerdem hat man keine Autovervollständigung, wenn man mit der Variable weiterarbeitet.

      const stateValues1: Record<string, string> = {
          stateA:  'State A',
          stateB:  'State B',
      }
      var stateId1 = 'javascript.0.state1';
      createState(stateId1, 'stateA', false, {
          name: 'Status 1',
          type: 'string',
          read: true,
          write: false,
          unit: '',
          role: 'state',
          states: stateValues1
      });  
      var value1 = getState(stateId1).val;
      log(value1.toString());
      var someVar1 = 'stateB';
      if(value1 == someVar1) {}
      var someVar1b = 'sateB'; // Typo
      if(value1 == someVar1b) {}
      setState(stateId1, value1)
      
      

      Man könnte auch mit Konstanten arbeiten, aber Autovervollständigung hat man dann bei den States nicht:

      const state3A = 'stateA';
      const state3B = 'stateB';
      type State3 = 'stateA' | 'stateB';
      
      const stateValues3: Record<State3, string> = {
          [state3A]:  'State A',
          [state3B]:  'State B',
      }
      var stateId3 = 'javascript.0.state3';
      createState(stateId3, state3A, false, {
          name: 'Status 3',
          type: 'string',
          read: true,
          write: false,
          unit: '',
          role: 'state',
          states: stateValues3
      }); 
      var value3: State3  = getState(stateId3).val;
      log(value3.toString());
      var someVar3: State3 = state3B;
      //var someVar3b: State3 = 'sateA'; <-- typo not allowed
      if(value3 == someVar3) {}
      setState(stateId3, value3);
      

      Am besten würden mir folgende Variante mit Enums gefallen. Allerdings ist hier der State mit numerischen Keys definiert (common.type: 'number'). common.states daher als Record<number, string> statt Record<string, string>

      enum States2 {
          stateA,
          stateB
      }
      const stateValues2: Record<States2, string> = {
          [States2.stateA]:  'State A',
          [States2.stateB]:  'State B'
      }
      var stateId2 = 'javascript.0.state2';
      createState(stateId2, States2.stateA, false, {
          name: 'Status 2',
          type: 'number',
          read: true,
          write: false,
          unit: '',
          role: 'state',
          states: stateValues2
      }); 
      var value2: States2  = getState(stateId2).val;
      log(value2.toString());
      var someVar2 = States2.stateB;
      if(value2 == someVar2) {}
      setState(stateId2, value2);
      

      Es ginge zwar mit Enums auch mit Record<string, string> - das wird aber kompliziert:

      enum States4 {
          stateA,
          stateB,
      }    
      
      const stateValues4: Record<string, string> = {
          [States4[States4.stateA]]:  'State A',
          [States4[States4.stateB]]:  'State B'
      }
      var stateId4 = 'javascript.0.state4';
      createState(stateId4, States4[States4.stateA], false, {
          name: 'Status 4',
          type: 'string',
          read: true,
          write: false,
          unit: '',
          role: 'state',
          states: stateValues4
      });  
      var value4: States4 = States4[getState(stateId4).val as string];
      log(value4.toString());
      var someVar4: States4 = States4.stateB;
      if(value4 == someVar4) {}
      setState(stateId4, States4[value4]);
      

      Ich bin keine Typescript-Profi - vielleicht gibt's noch bessere Varianten. Ich finde es halt am schönsten, wenn man so States im Code als Enums definiert, weil man dann keine Tippfehler machen kann und Autovervollständigen hat.
      Ist es ein Problem, wenn der common.state als Record<number, string> und der State als "number" definiert ist?

      paul53 AlCalzone 2 Replies Last reply Reply Quote 0
      • paul53
        paul53 @noox last edited by

        @noox
        common.states ist als Objekt mit einer Anzahl diskreter Werte (false/true oder 0/1/2/...) denen Zustandstexte zugewiesen werden, definiert. Was soll daran geändert werden ?

        N 1 Reply Last reply Reply Quote 0
        • AlCalzone
          AlCalzone Developer @noox last edited by

          @noox sagte in TypeScript und common.states (Record<string, string>):

          So ganz happy bin ich mit dem Record nicht, weil man zumindest im einfachsten Fall mit Zeichenketten herum hantiert, wo natürlich schnell mal ein Tippfehler passieren kann.

          Tippfehler abfangen in Objekten, die an Funktionen übergeben werden (wie der common-Teil an sich), funktioniert nur, wenn die Form des Objekts vorher bekannt ist. Im Falle von common.states ist das nicht gegeben, da hier jeder erdenklicher Key erlaubt ist.

          Zu number vs. string: Objekte in JS haben strings als Keys, selbst wenn du mit einer Zahl drauf zugreifst:

          "states": {
                "0": "ALL ON not active, ALL OFF not active",
                "1": "ALL ON not active, ALL OFF active",
                "2": "ALL ON active, ALL OFF not active",
                "255": "ALL ON active, ALL OFF active"
              }
          

          Deswegen ist bei Record<string, ...> auch der Zugriff mit numerischen Keys möglich:
          https://www.typescriptlang.org/play?#code/MYewdgzgLgBAZiEAuGAlApqATgEwDzRYCWYA5gDQwBGiANugIZgB8MAvDAN4C+A3AFAIQAbQBEARlEBddjChYArugFDh4mR3lLeQA


          Zweitens: Bist du gerade nicht eher beim Skripten im Skript-Adapter? ==> https://github.com/ioBroker/ioBroker.javascript/blob/master/lib/javascript.d.ts

          N 1 Reply Last reply Reply Quote 0
          • AlCalzone
            AlCalzone Developer last edited by

            @noox oder willst du erreichen, dass beim createState mit vorhandenem common.states geprüft wird, ob der übergebene Wert dazu passt? Das könnte gehen - aber nur, wenn der zu setzende Wert genau genug bekannt ist.

            Für die Nutzung mit Variablen steht man schon wieder vor dem Problem, dass irgendwie die Brücke zur State-Definition geschlagen werden muss - und das ohne den Code auszuführen.

            1 Reply Last reply Reply Quote 0
            • N
              noox @paul53 last edited by noox

              @paul53 said in TypeScript und common.states (Record<string, string>):

              @noox
              common.states ist als Objekt mit einer Anzahl diskreter Werte (false/true oder 0/1/2/...) denen Zustandstexte zugewiesen werden, definiert. Was soll daran geändert werden ?

              Die common.states können in JS ja auf verschiedensten Weise angegeben werden. In TypeScript ist zumindest die Definition mit Record<string, string> restriktiver. Mir geht's nicht um eine Änderung, sonder eher um eine Best Practice.

              Mir ist nämlich mehrmals aufgefallen, dass ich mich verhaut habe. Z.B. habe ich einen Record standardmäßig definiert. Man darf aber dann nicht den Fehler machen, den State mit dem Wert stateValues1.stateA (vom Record) zu erstellen oder auf diesen zu setzen. Weil stateValues1.stateA liefert den Value ('Status A') und nicht den Key. Fehler bekommt man allerdings keinen - d.h. wenn man es durchgängig macht, funktioniert es sogar.

              1 Reply Last reply Reply Quote 0
              • N
                noox @AlCalzone last edited by

                @AlCalzone said in TypeScript und common.states (Record<string, string>):

                Tippfehler abfangen in Objekten, die an Funktionen übergeben werden (wie der common-Teil an sich), funktioniert nur, wenn die Form des Objekts vorher bekannt ist. Im Falle von common.states ist das nicht gegeben, da hier jeder erdenklicher Key erlaubt ist.

                Mir geht's darum, dass ich den Wert eines Status dann in einer vernünftigen Form habe - eben z.B. ein Enum. Damit dann die weitere Fehleranfälligkeit geringer ist. Dass die States alle möglichen Werte akzeptieren, finde ich nicht so tragisch - insbesondere wenn ich eben vorher mit sauberen Typen bzw. Enums arbeiten kann, dann ist die Wahrscheinlichkeit eh gering, hier einen Fehler zu machen.

                Zu number vs. string: Objekte in JS haben strings als Keys, selbst wenn du mit einer Zahl drauf zugreifst:
                Deswegen ist bei Record<string, ...> auch der Zugriff mit numerischen Keys möglich:

                Damit ich die Enums verwenden kann, hatte ich den Record als Record<MyEnum, string> definiert. Allerdings vergessen, common.type von string auf number zu ändern. createState('id', MyEnum.enumValA, false, {...}); funktioniert trotzdem. setState('id', MyEnum.enumValA); funktioniert auch, liefert allerdings eine Warnung bei der Ausführung. Was ja eigentlich auch OK ist, weil der Enum-Wert ja eine number ist.

                Prinzipiell hat man einige Freiheiten bei den States, aber es gibt halt auch ein paar Fallen. Daher möchte ich mir halt eine Best Practice-Methode zurechtlegen. Aber denke, ich bleib bei Variante 3 mit dem Enum.

                Zweitens: Bist du gerade nicht eher beim Skripten im Skript-Adapter? ==> https://github.com/ioBroker/ioBroker.javascript/blob/master/lib/javascript.d.ts

                Danke!

                1 Reply Last reply Reply Quote 0
                • AlCalzone
                  AlCalzone Developer last edited by

                  Das was du (glaube ich) vor hast, kann man nicht statisch prüfen. Der Aufruf von setState('id', MyEnum.enumValA); hat für TypeScript nichts mit createState('id', MyEnum.enumValA, false, {...}); zu tun.

                  Außerdem kommt wie gesagt noch dazu, dass Record<string, string> ist bei den Keys auch flexibel ist - number geht aus Kompatibilitätsgründen zu JavaScript auch. Und Enums mit TypeChecking ist auch eher so lala.
                  Wenn du was findest, was für dich funktioniert, dann ists gut. Aber ich fürchte das global zu nutzen wird schwierig.

                  1 Reply Last reply Reply Quote 0
                  • First post
                    Last post

                  Support us

                  ioBroker
                  Community Adapters
                  Donate

                  981
                  Online

                  31.8k
                  Users

                  80.0k
                  Topics

                  1.3m
                  Posts

                  3
                  7
                  636
                  Loading More Posts
                  • Oldest to Newest
                  • Newest to Oldest
                  • Most Votes
                  Reply
                  • Reply as topic
                  Log in to reply
                  Community
                  Impressum | Datenschutz-Bestimmungen | Nutzungsbedingungen
                  The ioBroker Community 2014-2023
                  logo