Dictionary 在Typescript中声明并初始化字典

Dictionary 在Typescript中声明并初始化字典,dictionary,initialization,typescript,Dictionary,Initialization,Typescript,给定以下代码 interface IPerson { firstName: string; lastName: string; } var persons: { [id: string]: IPerson; } = { "p1": { firstName: "F1", lastName: "L1" }, "p2": { firstName: "F2" } }; 为什么初始化没有被拒绝?毕竟,第二个对象没有“lastName”属性。Edit:这已在最新的TS版本中修复。

给定以下代码

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

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

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

Edit:这已在最新的TS版本中修复。引用@Simon_Weaver对OP帖子的评论:


注意:这已被修复(不确定确切的TS版本)。我 如您所料,在VS中获取这些错误:
索引签名是
不相容的类型“{firstName:string;}”不可分配给类型
“伊佩森”。类型{firstName:
字符串;}.


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

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

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

我同意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;
    }
}
下面是一个简单的初始化和使用示例:

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

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

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

要在typescript中使用dictionary对象,可以使用如下界面:

interface Dictionary<T> {
    [Key: string]: T;
}
接口字典{
[键:字符串]:T;
}
并且,将其用于类属性类型

export class SearchParameters {
    SearchFor: Dictionary<string> = {};
}
导出类搜索参数{
SearchFor:Dictionary={};
}
要使用和初始化该类

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));
    }
getUsers():可观察{
var searchParams=新的SearchParameters();
searchParams.SearchFor['userId']='1';
searchParams.SearchFor['userName']='xyz';
返回此.http.post(searchParams,'users/search')
.map(res=>{
返回res;
})
抓住(这个)手,绑(这个);
}

这里是一个更通用的字典实现,它的灵感来自@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;
      }
    }
接口IDictionary{ add(key:string,value:T):void; 移除(键:字符串):无效; containsKey(键:字符串):布尔值; keys():字符串[]; 值():T[]; } 类字典实现IDictionary{ _键:字符串[]=[]; _值:T[]=[]; 构造函数(init?:{key:string;value:T;}[]{ if(init){ 对于(var x=0;xTypescript在您的案例中失败,因为它希望所有字段都存在。使用记录和部分实用程序类型来解决此问题

记录

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

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

非常有用的示例代码。“接口IDictionary”包含一个小的输入错误,因为有一个对IPerson的引用well@dmck声明
包含skey(key:string):bool不适用于TypeScript 1.5.0-beta。应将其更改为
containsKey(键:string):布尔值。为什么不删除泛型类型?字典,则无需创建PersonDictionary类。您可以这样声明:var persons=newdictionary();我有效地使用了这样一本通用词典。我发现它在这里:注意:这已经被修复(不知道确切的TS版本)。正如您所料,我在VS中遇到这些错误:
索引签名不兼容。
类型“{firstName:string;}”不可分配给类型“IPerson”。
类型“{firstName:string;}”中缺少属性“lastName”“.
你能更新这篇文章吗:标题与问题和接受的答案不一致!在正式的typescript手册中,允许我们制作类似于typescript中的字典的概念被称为“可索引类型”(参见)。因为我花了一段时间才发现这一点,所以我想通过为该功能提供“官方名称”,为每个搜索官方文档的人指明正确的方向。为什么需要
id
符号?似乎没有必要。使用
id
符号,可以声明字典键的类型。使用上面的声明,您无法执行以下操作:
persons[1]={firstName:'F1',lastName:'L1'}
id
符号可以被命名为任何您喜欢的名称,其设计目的是使代码更容易阅读。e、 g.
{[username:string]:IPerson;}
问题的关键是,为什么给定的代码在编译时没有提供姓氏…
interface IPerson {
   firstName: string;
   lastName: string;
}

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