403 Stimmen

Deklariere und initialisiere ein Wörterbuch in Typescript

Angesichts des folgenden Codes

Schnittstelle IPerson {
   firstName: string;
   lastName: string;
}

var personen: { [id: string]: IPerson; } = {
   "p1": { firstName: "F1", lastName: "L1" },
   "p2": { firstName: "F2" }
};

Warum wird die Initialisierung nicht abgelehnt? Immerhin hat das zweite Objekt nicht die Eigenschaft "lastName".

432voto

thomaux Punkte 18280

Bearbeiten: Dies wurde in den neuesten TS-Versionen behoben. Zitat von @Simon_Weaver's Kommentar zum Beitrag des OP:

Hinweis: Dies wurde inzwischen behoben (nicht sicher, in welcher genauen TS-Version). Ich erhalte diese Fehler in VS, wie zu erwarten: Index-Signaturen sind inkompatibel. Der Typ '{ firstName: string; }' ist nicht zuweisbar zum Typ 'IPerson'. Das Attribut 'lastName' fehlt im Typ '{ firstName: string; }'.


Offenbar funktioniert dies nicht, wenn die initialen Daten bei der Deklaration übergeben werden. Ich vermute, dass dies ein Fehler in TypeScript ist, also sollten Sie dies auf der Projektseite melden.

Sie können das typisierte Dictionary nutzen, indem Sie Ihr Beispiel in Deklaration und Initialisierung aufteilen, wie folgt:

var persons: { [id: string] : IPerson; } = {};
persons["p1"] = { firstName: "F1", lastName: "L1" };
persons["p2"] = { firstName: "F2" }; // wird zu einem Fehler führen

158voto

Amol Bhor Punkte 2019

Für die Verwendung des Wörterbuchobjekts in TypeScript können Sie das Interface wie folgt verwenden:

interface Dictionary {
    [Key: string]: T;
}

und verwenden Sie dies für den Typ Ihres Klassenattributs.

export class SearchParameters {
    SearchFor: Dictionary = {};
}

Um diese Klasse zu verwenden und zu initialisieren,

getUsers(): Observable {
        var searchParams = new SearchParameters();
        searchParams.SearchFor['userId'] = '1';
        searchParams.SearchFor['userName'] = 'xyz';

        return this.http.post(searchParams, 'users/search')
            .map(res => {
                return res;
            })
            .catch(this.handleError.bind(this));
    }

67voto

dmck Punkte 7661

Ich stimme thomaux zu, dass der Initialisierungsfehler für den Typencheck ein TypeScript-Bug ist. Ich wollte jedoch immer noch einen Weg finden, ein Dictionary in einer einzigen Anweisung mit korrektem Typencheck zu deklarieren und zu initialisieren. Diese Implementierung ist länger, jedoch fügt sie zusätzliche Funktionen wie eine containsKey(key: string) und remove(key: string) Methode hinzu. Ich vermute, dass dies vereinfacht werden könnte, sobald Generics in der Version 0.9 verfügbar sind.

Zuerst deklarieren wir die Basisklasse und das Interface für das Dictionary. Das Interface wird für den Indexer benötigt, da Klassen sie nicht implementieren können.

interface IDictionary {
    add(key: string, value: any): void;
    remove(key: string): void;
    containsKey(key: string): boolean;
    keys(): string[];
    values(): any[];
}

class Dictionary {

    _keys: string[] = new Array();
    _values: any[] = new Array();

    constructor(init: { key: string; value: any; }[]) {

        for (var x = 0; x < init.length; x++) {
            this[init[x].key] = init[x].value;
            this._keys.push(init[x].key);
            this._values.push(init[x].value);
        }
    }

    add(key: string, value: any) {
        this[key] = value;
        this._keys.push(key);
        this._values.push(value);
    }

    remove(key: string) {
        var index = this._keys.indexOf(key, 0);
        this._keys.splice(index, 1);
        this._values.splice(index, 1);

        delete this[key];
    }

    keys(): string[] {
        return this._keys;
    }

    values(): any[] {
        return this._values;
    }

    containsKey(key: string) {
        if (typeof this[key] === "undefined") {
            return false;
        }

        return true;
    }

    toLookup(): IDictionary {
        return this;
    }
}

Jetzt deklarieren wir den spezifischen Typ Person und das Dictionary/Dictionary-Interface. Im PersonDictionary sehen Sie, wie wir values() und toLookup() überschreiben, um die richtigen Typen zurückzugeben.

interface IPerson {
    firstName: string;
    lastName: string;
}

interface IPersonDictionary extends IDictionary {
    [index: string]: IPerson;
    values(): IPerson[];
}

class PersonDictionary extends Dictionary {
    constructor(init: { key: string; value: IPerson; }[]) {
        super(init);
    }

    values(): IPerson[]{
        return this._values;
    }

    toLookup(): IPersonDictionary {
        return this;
    }
}

Und hier ist ein einfaches Initialisierungs- und Verwendungsbeispiel:

var persons = new PersonDictionary([
    { key: "p1", value: { firstName: "F1", lastName: "L2" } },
    { key: "p2", value: { firstName: "F2", lastName: "L2" } },
    { key: "p3", value: { firstName: "F3", lastName: "L3" } }
]).toLookup();

alert(persons["p1"].firstName + " " + persons["p1"].lastName);
// alert: F1 L2

persons.remove("p2");

if (!persons.containsKey("p2")) {
    alert("Schlüssel existiert nicht mehr");
    // alert: Schlüssel existiert nicht mehr
}

alert(persons.keys().join(", "));
// alert: p1, p3

25voto

aWebDeveloper Punkte 33447

Typescript scheitert in Ihrem Fall, weil es erwartet, dass alle Felder vorhanden sind. Verwenden Sie die Dienstprogrammtypen Record und Partial, um das Problem zu lösen.

Record>

interface IPerson {
   firstName: string;
   lastName: string;
}

var persons: Record> = {
   "p1": { firstName: "F1", lastName: "L1" },
   "p2": { firstName: "F2" }
};

Erklärung.

  1. Record Typ erstellt ein Wörterbuch/Hashmap.
  2. Partial Typ besagt, dass einige der Felder fehlen können.

Alternativ.

Wenn Sie den Nachnamen optional machen möchten, können Sie ein ? anhängen. Typescript wird wissen, dass es optional ist.

lastName?: string;

https://www.typescriptlang.org/docs/handbook/utility-types.html

11voto

mbcom Punkte 188

Hier ist eine allgemeinere Implementierung eines Wörterbuchs, die von diesem von @dmck inspiriert wurde

      Schnittstelle IDictionary {
          hinzufügen (Schlüssel: string, Wert: T): void;
          entfernen (Schlüssel: string): void;
          enthältSchlüssel (Schlüssel: string): boolean;
          schlüssel(): string[];
          Werte(): T[];
        }

        Klasse Wörterbuch implementiert IDictionary {

          _schlüssel: string[] = [];
          _werte: T[] = [];

          Konstruktor(init?: {schlüssel: string; wert: T; }[]) {
            wenn (init) {
              für (var x = 0; x < init.length; x++) {
                this[init[x].schlüssel] = init[x].wert;
                this._schlüssel.push(init[x].schlüssel);
                this._werte.push(init[x].wert);
              }
            }
          }

          hinzufügen(schlüssel: string, wert: T) {
            this[schlüssel] = wert;
            this._schlüssel.push(schlüssel);
            this._werte.push(wert);
          }

          entfernen(schlüssel: string) {
            var index = this._schlüssel.indexOf(schlüssel, 0);
            this._schlüssel.splice(index, 1);
            this._werte.splice(index, 1);

            delete this[schlüssel];
          }

          schlüssel(): string[] {
            return this._schlüssel;
          }

          Werte(): T[] {
            return this._werte;
          }

          enthältSchlüssel(schlüssel: string) {
            if (typeof this[schlüssel] === "undefined") {
              return false;
            }

            return true;
          }

          toLookup(): IDictionary {
            return this;
          }
        }

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X