Daktilo Yazısında Sözlük Bildirme ve Başlatma


248

Aşağıdaki kod verildiğinde

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

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

Başlatma neden reddedilmedi? Sonuçta, ikinci nesnenin "lastName" özelliği yoktur.


11
Not: Bu o zamandan beri düzeltildi (hangi kesin TS versiyonundan emin değilim). Bu hataları Index signatures are incompatible. Type '{ firstName: string; }' is not assignable to type 'IPerson'. Property 'lastName' is missing in type '{ firstName: string; }'.
VS'de

Yanıtlar:


289

Düzenleme : Bu, en son TS sürümlerinde düzeltildi. @ Simon_Weaver'ın OP yayınına yaptığı yorumdan alıntı:

Not: Bu o zamandan beri düzeltildi (hangi kesin TS versiyonundan emin değilim). Beklediğiniz gibi VS bu hataları alıyorum:Index signatures are incompatible. Type '{ firstName: string; }' is not assignable to type 'IPerson'. Property 'lastName' is missing in type '{ firstName: string; }'.


Görünüşe göre bu, beyanda ilk verileri iletirken işe yaramaz. Sanırım bu TypeScript'te bir hata, bu yüzden proje sitesinde bir tane yükseltmelisiniz.

Yazdığınız sözlüğü, beyan ve başlatma işleminde örneğinizi bölerek kullanabilirsiniz, örneğin:

var persons: { [id: string] : IPerson; } = {};
persons["p1"] = { firstName: "F1", lastName: "L1" };
persons["p2"] = { firstName: "F2" }; // will result in an error

3
Neden idsembole ihtiyacınız var ? Gereksiz gibi görünüyor.
kiewic

4
Simgesini kullanarak, idsözlüğün anahtarlarının türünün ne olacağını bildirebilirsiniz. Yukarıdaki beyan ile aşağıdakileri yapamazsınız:persons[1] = { firstName: 'F1', lastName: 'L1' }
thomaux

2
Nedense bu sözdizimini daima unutun!
eddiewould

12
idsembolü gibi bir şey seni adlandırılabilir ve daha kolay kod okunmasını sağlamak için bu şekilde tasarlanmıştır. ör. { [username: string] : IPerson; }
Guy Park

1
@Robouste Lodash 'findKey yöntemini kullanırdım ya da yerel bir çözüm tercih ederseniz, Object.entries üzerine inşa edebilirsiniz . Anahtarların tam listesini almakla ilgileniyorsanız, Object.keys
thomaux

82

Daktiloda sözlük nesnesini kullanmak için arayüzü aşağıdaki gibi kullanabilirsiniz:

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

ve bunu sınıf özellik türünüz için kullanın.

export class SearchParameters {
    SearchFor: Dictionary<string> = {};
}

bu sınıfı kullanmak ve başlatmak,

getUsers(): Observable<any> {
        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));
    }

61

Thomaux ile başlatma tipi kontrol hatasının bir TypeScript hatası olduğunu kabul ediyorum. Ancak, yine de doğru tür denetimi ile tek bir ifadede bir Sözlük bildirmek ve başlatmak için bir yol bulmak istedim. Bu uygulama daha uzundur, ancak a containsKey(key: string)ve remove(key: string)yöntem gibi ek işlevler ekler . 0.9 sürümünde jenerikler mevcut olduğunda bunun basitleştirilebileceğinden şüpheleniyorum.

İlk önce temel Sözlük sınıfını ve Arabirimini bildiririz. Sınıflar bunları uygulayamadığından, arabirim dizinleyici için gereklidir.

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

class Dictionary {

    _keys: string[] = new string[];
    _values: any[] = new any[];

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

Şimdi Kişiye özgü tür ve Sözlük / Sözlük arayüzünü ilan ediyoruz. PersonDictionary not nasıl geçersiz kılmak values()ve toLookup()doğru türleri döndürmek için.

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

İşte basit bir başlatma ve kullanım örneği:

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("Key no longer exists");
    // alert: Key no longer exists
}

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

Çok yararlı örnek kod. "Arabirim IDictionary", IPerson'a bir başvuru olduğu için küçük bir yazım hatası içerir.
mgs

eleman sayısını da uygulamak iyi olurdu
nurettin

@dmck Bildirim containsKey(key: string): bool;, TypeScript 1.5.0-beta ile çalışmaz . Olarak değiştirilmelidir containsKey(key: string): boolean;.
Amarjeet Singh

1
neden jenerik tip delcare yok? Sözlük <T>, sonra PersonDictionary sınıfı oluşturmaya gerek yok. Bunu şöyle beyan edersiniz: var persons = new Dictionary <IPerson> ();
Benoit

1
Böyle genel bir sözlüğü etkili bir şekilde kullandım. Burada buldum: fabiolandoni.ch/…
CAK2

5

İşte @dmck'ten ilham alan daha genel bir Sözlük uygulaması

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

    class Dictionary<T> implements IDictionary<T> {

      _keys: string[] = [];
      _values: T[] = [];

      constructor(init?: { key: string; value: T; }[]) {
        if (init) {
          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: T) {
        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(): T[] {
        return this._values;
      }

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

        return true;
      }

      toLookup(): IDictionary<T> {
        return this;
      }
    }

3

Bir özelliği yok saymak istiyorsanız, soru işareti ekleyerek özelliği isteğe bağlı olarak işaretleyin:

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

1
Sorunun asıl amacı, verilen kodun soyadı verilmeden neden derlendiğidir ...
Pierre Arlaud

-1

Şimdi, daktiloda güçlü yazılan, sorgulanabilir koleksiyonlar sağlayan bir kütüphane var .

Bu koleksiyonlar:

  • Liste
  • Sözlük

Kütüphaneye ts-generic-collections-linq adı verilir .

GitHub'daki kaynak kodu:

https://github.com/VeritasSoftware/ts-generic-collections

NPM:

https://www.npmjs.com/package/ts-generic-collections-linq

Bu kütüphane ile, koleksiyonlar oluşturabilir (gibi List<T>) ve aşağıda gösterildiği gibi sorgulayabilirsiniz.

    let owners = new List<Owner>();

    let owner = new Owner();
    owner.id = 1;
    owner.name = "John Doe";
    owners.add(owner);

    owner = new Owner();
    owner.id = 2;
    owner.name = "Jane Doe";
    owners.add(owner);    

    let pets = new List<Pet>();

    let pet = new Pet();
    pet.ownerId = 2;
    pet.name = "Sam";
    pet.sex = Sex.M;

    pets.add(pet);

    pet = new Pet();
    pet.ownerId = 1;
    pet.name = "Jenny";
    pet.sex = Sex.F;

    pets.add(pet);

    //query to get owners by the sex/gender of their pets
    let ownersByPetSex = owners.join(pets, owner => owner.id, pet => pet.ownerId, (x, y) => new OwnerPet(x,y))
                               .groupBy(x => [x.pet.sex])
                               .select(x =>  new OwnersByPetSex(x.groups[0], x.list.select(x => x.owner)));

    expect(ownersByPetSex.toArray().length === 2).toBeTruthy();

    expect(ownersByPetSex.toArray()[0].sex == Sex.F).toBeTruthy();
    expect(ownersByPetSex.toArray()[0].owners.length === 1).toBeTruthy();
    expect(ownersByPetSex.toArray()[0].owners.toArray()[0].name == "John Doe").toBeTruthy();

    expect(ownersByPetSex.toArray()[1].sex == Sex.M).toBeTruthy();
    expect(ownersByPetSex.toArray()[1].owners.length == 1).toBeTruthy();
    expect(ownersByPetSex.toArray()[1].owners.toArray()[0].name == "Jane Doe").toBeTruthy();

Bunun için bir npm paketi bulamıyorum
Harry

1
@Harry - npm paketi "ts-generic-collections-linq" olarak adlandırılıyor
Ade
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.