Відповіді:
Редагувати : з тих пір це було виправлено в останніх версіях TS. Цитуючи коментар @ Simon_Weaver до повідомлення ОП:
Примітка: з тих пір це було виправлено (не впевнено, яка саме версія ТС). Я отримую ці помилки в VS, як ви і очікували:
Index signatures are incompatible. Type '{ firstName: string; }' is not assignable to type 'IPerson'. Property 'lastName' is missing in type '{ firstName: string; }'.
Ви можете скористатися введеним словником, розділивши приклад на декларацію та ініціалізацію, наприклад:
var persons: { [id: string] : IPerson; } = {};
persons["p1"] = { firstName: "F1", lastName: "L1" };
persons["p2"] = { firstName: "F2" }; // will result in an error
id
символ? Здається, це зайве.
id
символ, можна оголосити, яким має бути тип ключів словника. З вищезазначеною декларацією ви не можете зробити наступне:persons[1] = { firstName: 'F1', lastName: 'L1' }
id
символ можна назвати все , що ви , як і був розроблений таким чином , щоб зробити його більш зручним для читання коду. наприклад { [username: string] : IPerson; }
Для використання об'єкта словника в typecript ви можете використовувати інтерфейс, як показано нижче:
interface Dictionary<T> {
[Key: string]: T;
}
і, використовуйте це для типу властивості вашого класу.
export class SearchParameters {
SearchFor: Dictionary<string> = {};
}
використовувати та ініціалізувати цей клас,
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));
}
Я погоджуюся з thomaux, що помилка перевірки типу ініціалізації - помилка TypeScript. Однак я все ж хотів знайти спосіб декларування та ініціалізації Словника в одному операторі з правильною перевіркою типу. Ця реалізація довша, проте вона додає додаткові функціональні можливості, такі як containsKey(key: string)
і remove(key: string)
метод. Я підозрюю, що це може бути спрощено, коли доступні дженерики у версії 0.9.
Спочатку ми оголосимо базовий клас словника та інтерфейс. Інтерфейс необхідний для індексатора, оскільки класи не можуть їх реалізувати.
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;
}
}
Тепер ми оголошуємо особовий тип та інтерфейс словника / словника. У PersonDictionary відзначте, як ми перекриваємо values()
та toLookup()
повертаємо правильні типи.
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;
}
}
Ось простий приклад ініціалізації та використання:
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
containsKey(key: string): bool;
не працює з TypeScript 1.5.0-beta . Це слід змінити на containsKey(key: string): boolean;
.
Ось більш загальна реалізація словника, натхненна цим від @dmck
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;
}
}
Якщо ви хочете ігнорувати ресурс, позначте його як необов’язковий, додавши знак питання:
interface IPerson {
firstName: string;
lastName?: string;
}
Тепер є бібліотека, яка забезпечує сильно типізовані, запитувані колекції в машинопис.
Ці колекції:
Бібліотека називається ts-generic-collection-linq .
Вихідний код на GitHub:
https://github.com/VeritasSoftware/ts-generic-collections
NPM:
https://www.npmjs.com/package/ts-generic-collections-linq
За допомогою цієї бібліотеки ви можете створювати колекції (як List<T>
) і запитувати їх, як показано нижче.
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();
Index signatures are incompatible.
Type '{ firstName: string; }' is not assignable to type 'IPerson'.
Property 'lastName' is missing in type '{ firstName: string; }'.