C # gibi Sözlük türleri olarak TypeScript Nesneleri


336

Sözlükler olarak nesneleri kullanan bazı JavaScript kodu var; örneğin, bir 'kişi' nesnesi e-posta adresini kilitleyen bazı kişisel ayrıntıları saklar.

var people = {<email> : <'some personal data'>};

adding   > "people[<email>] = <data>;" 
getting  > "var data = people[<email>];" 
deleting > "delete people[<email>];"

Bunu Daktiloda tanımlamak mümkün mü? veya Array kullanmam gerekir mi?


5
Eski yazı ama ES6 Haritası olduğunu unutmayın
Eski Badman Gray

Yanıtlar:


547

Dizginin yeni sürümlerinde şunları kullanabilirsiniz:

type Customers = Record<string, Customer>

Eski sürümlerde şunları kullanabilirsiniz:

var map: { [email: string]: Customer; } = { };
map['foo@gmail.com'] = new Customer(); // OK
map[14] = new Customer(); // Not OK, 14 is not a string
map['bar@hotmail.com'] = 'x'; // Not OK, 'x' is not a customer

Ayrıca, her defasında bu tür ek açıklamayı yazmak istemiyorsanız bir arayüz de yapabilirsiniz:

interface StringToCustomerMap {
    [email: string]: Customer;
}

var map: StringToCustomerMap = { };
// Equivalent to first line of above

2
Bu, derleyicinin dizinleri dizelerle kısıtladığından emin olmanın yararlı bir yoludur. İlginç. Dizin türünü dizeler veya tamsayılardan başka bir şey olarak belirtebileceğiniz gibi görünmüyor, ancak yalnızca yerel JS nesne dizinleriyle eşleştiği için mantıklı.
Ken Smith

5
Bunu biliyor olabilirsiniz, ancak bu yaklaşımla ilgili bazı potansiyel anlaşmalar da var, büyük olan, tüm üyeler arasında tekrar etmenin güvenli ve kolay bir yolu olmadığıdır. Bu kod, örneğin, mapiki üye içerdiğini gösterir : (<any> Object.prototype) .something = function () {}; sınıf Müşteri {} var map: {[email: string]: Müşteri; } = {}; map ['foo@gmail.com '] = yeni Müşteri (); for (haritadaki var i) {console.log (harita [i])}
Ken Smith

5
ondan nasıl çıkarıyorsun?
TDaver

24
Bir başka ilginç yaklaşım: MapStringTo <T> {[key: string] arayüzü: T; } Ve değişken gibi ilanvar map:MapStringTo<Customer> = {};
orellabac

1
Dizin kısıtlamasının artık çalışmadığını unutmayın. Daha fazla oku.
David Sherret

127

Eşleme benzeri bir nesne kullanmaya ek olarak, bir süredir ES6'ya derlerken veya ES6 tür tanımlarıyla çok amaçlı bir dolgu kullanırken TypeScript'te kullanılabilen gerçek bir Mapnesne olmuştur :

let people = new Map<string, Person>();

ObjectBiraz farklı bir sözdizimiyle aynı işlevi ve daha fazlasını destekler :

// Adding an item (a key-value pair):
people.set("John", { firstName: "John", lastName: "Doe" });

// Checking for the presence of a key:
people.has("John"); // true

// Retrieving a value by a key:
people.get("John").lastName; // "Doe"

// Deleting an item by a key:
people.delete("John");

Bunun tek başına harita benzeri bir nesnenin kullanımına göre çeşitli avantajları vardır , örneğin:

  • Her ikisi de tarafından desteklenmeyen Object(hayır, Objectsayıları desteklemiyorsa, bunları dizelere dönüştürür) dize tabanlı olmayan anahtarlar, örneğin sayılar veya nesneler için destek
  • Her zaman bir anahtar türü ve bir değer türü --noImplicitAnyolduğu için, kullanılmadığında hatalara daha az yer varken, bir nesnenin dizin imzası olmayabilirMap
  • Öğe ekleme / kaldırma (anahtar / değer çiftleri) işlevselliği , birObject

Buna ek olarak, bir Mapnesne, ortak görevler için birçoğu Objectyardımcı işlevleri hacklemeden basit s aracılığıyla kullanılamayan daha güçlü ve zarif bir API sağlar (bunlardan bazıları ES5 hedefleri veya altında tam bir ES6 yineleyici / yinelenebilir poli dolgu gerektirir):

// Iterate over Map entries:
people.forEach((person, key) => ...);

// Clear the Map:
people.clear();

// Get Map size:
people.size;

// Extract keys into array (in insertion order):
let keys = Array.from(people.keys());

// Extract values into array (in insertion order):
let values = Array.from(people.values());

2
Bu harika! Ama ne yazık ki kullanarak seri serileştirildi JSON.stringify(), bu yüzden örneğin socket.io için kullanılabilir :(
Lion

@Lion - evet, Mapserileştirme oldukça komik. Birincisi, serileştirmeden önce anahtar / değer çifti nesnelerine bir dönüşüm gerçekleştiriyorum ve sonra geri (örneğin nesnesi { key: "John", value: { firstName: "John" } }).
John Weisz

2
Eski bir nesne yerine bir harita kullanma hatasını yaptım ve serileştirme gerçekten beni yakaladı. Bence net bir şekilde yönlendirin.
user378380

1
Bu güzel. Sonunda haritalara dalmama ilham verdiğin için çok mutluyum. Bu, her zamanki tuş eşlemem / sözlük yapılarımın yerini alacak, çünkü anahtarları güçlü bir şekilde yazmak çok daha kolay.
Methodician

77

Bu gibi şablonlanmış arayüzler kullanabilirsiniz:

interface Map<T> {
    [K: string]: T;
}

let dict: Map<number> = {};
dict["one"] = 1;

7
Bunun es6 Harita türüyle çarpıştığını unutmayın. Dizin kısıtlaması yok sayıldığı için diğer yanıttan daha iyi.
Old Badman Gray

sözlükte bir anahtar olup olmadığını nasıl kontrol edebilirim?
samneric

dict.hasOwnProperty ('anahtar')
Dimitar Mazhlekov

1
Karışıklık önlemek için harita yerine sözlük kullanın ve değişmez nesne gösterimi kullanabilirsiniz:let dict: Dictionary<number> = { "one": 1, "two": 2 };
PhiLho

8

Kayıt türünü yazı tipinde de kullanabilirsiniz:

export interface nameInterface { 
    propName : Record<string, otherComplexInterface> 
}

5

Lodash basit bir Sözlük uygulamasına sahiptir ve iyi bir TypeScript desteğine sahiptir

Lodash'ı yükleyin:

npm install lodash @types/lodash --save

İthalat ve kullanım:

import { Dictionary } from "lodash";
let properties : Dictionary<string> = {
    "key": "value"        
}
console.log(properties["key"])

3

Bunun için kullanabilirsiniz Record:

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

Örnek (AppointmentStatus enum ile bazı meta veriler arasında bir eşleme):

  const iconMapping: Record<AppointmentStatus, Icon> = {
    [AppointmentStatus.Failed]: { Name: 'calendar times', Color: 'red' },
    [AppointmentStatus.Canceled]: { Name: 'calendar times outline', Color: 'red' },
    [AppointmentStatus.Confirmed]: { Name: 'calendar check outline', Color: 'green' },
    [AppointmentStatus.Requested]: { Name: 'calendar alternate outline', Color: 'orange' },
    [AppointmentStatus.None]: { Name: 'calendar outline', Color: 'blue' }
  }

Şimdi değer olarak arayüz ile:

interface Icon { Name: string Color: string }

Kullanımı:

const icon: SemanticIcon = iconMapping[appointment.Status]


Bu çok faydalı. Eğer bir dize kullanabilirsiniz misiniz enumveya bir class/objectiçin AppointmentStatus- veya fark eder?
Drenai

@Drenai önemli değil, tercih ettiğiniz şey
Nick N.

-2

Yazı tipinde güçlü tip, sorgulanabilir koleksiyonlar sağlayan bir kütüphane bulunmaktadır .

Koleksiyonlar:

  • Liste
  • Sözlük

Kütüphaneye ts-generic-collections adı verilir . ( GitHub'daki kaynak kodu )

Bir sözlük oluşturabilir ve aşağıdaki gibi sorgulayabilirsiniz:

  it('firstOrDefault', () => {
    let dictionary = new Dictionary<Car, IList<Feature>>();

    let car = new Car(1, "Mercedez", "S 400", Country.Germany);
    let car2 = new Car(2, "Mercedez", "S 500", Country.Germany);

    let features = new List<Feature>();

    let feature = new Feature(1, "2 - Door Sedan");
    features.add(feature);

    dictionary.add(car, features);

    features = new List<Feature>();
    feature = new Feature(2, "4 - Door Sedan");
    features.add(feature);

    dictionary.add(car2, features);

    //query
    let first = dictionary.firstOrDefault(x => x.key.name == "Mercedez");

    expect(first.key.id = 1);
  });
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.