在 Typescript 中声明并初始化字典

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/15877362/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-11 01:03:03  来源:igfitidea点击:

Declare and initialize a Dictionary in Typescript

dictionaryinitializationtypescript

提问by mgs

Given the following code

鉴于以下代码

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

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

Why isn't the initialization rejected? After all, the second object does not have the "lastName" property.

为什么初始化没有被拒绝?毕竟,第二个对象没有“lastName”属性。

回答by thomaux

Edit: This has since been fixed in the latest TS versions. Quoting @Simon_Weaver's comment on the OP's post:

编辑:此问题已在最新的 TS 版本中得到修复。引用@Simon_Weaver 对 OP 帖子的评论:

Note: this has since been fixed (not sure which exact TS version). I get these errors in VS, as you would expect: Index signatures are incompatible. Type '{ firstName: string; }' is not assignable to type 'IPerson'. Property 'lastName' is missing in type '{ firstName: string; }'.

注意:此后已修复(不确定确切的 TS 版本)。正如您所料,我在 VS 中遇到了这些错误:Index signatures are incompatible. Type '{ firstName: string; }' is not assignable to type 'IPerson'. Property 'lastName' is missing in type '{ firstName: string; }'.



显然,这在声明时传递初始数据时不起作用。我猜这是 TypeScript 中的一个错误,因此您应该在项目站点上提出一个错误。

You can make use of the typed dictionary by splitting your example up in declaration and initialization, like:

您可以通过在声明和初始化中拆分示例来使用类型化字典,例如:

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

回答by Amol Bhor

For using dictionary object in typescript you can use interface as below:

要在打字稿中使用字典对象,您可以使用如下接口:

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

and, use this for your class property type.

并且,将此用于您的类属性类型。

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

to use and initialize this class,

使用和初始化这个类,

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

回答by dmck

I agree with thomaux that the initialization type checking error is a TypeScript bug. However, I still wanted to find a way to declare and initialize a Dictionary in a single statement with correct type checking. This implementation is longer, however it adds additional functionality such as a containsKey(key: string)and remove(key: string)method. I suspect that this could be simplified once generics are available in the 0.9 release.

我同意 thomaux 的观点,即初始化类型检查错误是一个 TypeScript 错误。但是,我仍然想找到一种方法来在单个语句中声明和初始化字典,并进行正确的类型检查。此实现更长,但它添加了附加功能,例如 acontainsKey(key: string)remove(key: string)方法。我怀疑一旦泛型在 0.9 版本中可用,这可以简化。

First we declare the base Dictionary class and Interface. The interface is required for the indexer because classes cannot implement them.

首先我们声明基本的 Dictionary 类和接口。索引器需要该接口,因为类无法实现它们。

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

Now we declare the Person specific type and Dictionary/Dictionary interface. In the PersonDictionary note how we override values()and toLookup()to return the correct types.

现在我们声明 Person 特定类型和 Dictionary/Dictionary 接口。在 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;
    }
}

And here is a simple initialization and usage example:

这是一个简单的初始化和使用示例:

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

回答by mbcom

Here is a more general Dictionary implementation inspired by this from @dmck

这是一个更通用的字典实现,灵感来自@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;
      }
    }

回答by mbcom

If you want to ignore a property, mark it as optional by adding a question mark:

如果您想忽略某个属性,请通过添加问号将其标记为可选:

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

回答by John

Now, there is a library which provides strongly-typed, queryable collectionsin typescript.

现在,有一个库可以在打字稿中提供强类型、可查询的集合

These collections are:

这些集合是:

  • List
  • Dictionary
  • 列表
  • 字典

The library is called ts-generic-collections-linq.

该库名为ts-generic-collections-linq

Source code on GitHub:

GitHub 上的源代码:

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

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

NPM:

新产品管理:

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

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

With this library, you can create collections (like List<T>) and query them as shown below.

使用此库,您可以创建集合(如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();