在 Typescript 中声明并初始化字典

问题描述 投票:0回答:9

给出以下代码

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

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

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

dictionary initialization typescript
9个回答
466
投票

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

注意:此问题已得到修复(不确定具体是哪个 TS 版本)。我 正如您所期望的,在 VS 中出现这些错误:

Index signatures are
  incompatible. Type '{ firstName: string; }' is not assignable to type
  'IPerson'. Property 'lastName' is missing in type '{ firstName:
  string; }'.


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

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

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

174
投票

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

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

69
投票

我同意 thomaux 的观点,初始化类型检查错误是一个 TypeScript bug。但是,我仍然想找到一种在单个语句中声明和初始化字典并进行正确类型检查的方法。此实现较长,但它添加了额外的功能,例如

containsKey(key: string)
remove(key: string)
方法。我怀疑一旦 0.9 版本中提供了泛型,这可以得到简化。

首先我们声明基本的 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;
    }
}

现在我们声明 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;
    }
}

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

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

36
投票

Typescript 在您的情况下失败,因为它期望所有字段都存在。使用 Record 和 Partial 实用程序类型来解决它。

Record<string, Partial<IPerson>>

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

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

解释。

  1. Record类型创建字典/哈希图。
  2. Partial 类型表示某些字段可能丢失。

替代。

如果您希望姓氏可选,您可以附加一个? Typescript 会知道它是可选的。

lastName?: string;

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


14
投票

Record 有点像 C# 字典

let myRecord: Record<string, number> = {}; 

//Add
myRecord[”key1”] = 1;

//Remove
delete myRecord[”key1"];

//Loop
for (var key in myRecord) {
    var value = myRecord[key];
}

11
投票

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

9
投票

如果您正在寻找一种即使在打字稿中也能创建字典的简单方法,那就是使用 Map 对象。文档链接 https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map 。 Map对象主要有添加、检索、删除和移除所有元素的方法。

dictionary= new Map<string, string>();
dictionary.set("key", "value");
dictionary.get("key");
dictionary.delete("key");
dictionary.clear(); //Removes all key-value pairs

5
投票

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

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

0
投票

可以参考下面的字典实现 创建类似 csharp 字典的 Typescript 字典类型

© www.soinside.com 2019 - 2024. All rights reserved.