2013-04-08 97 views
115

初始化字典考虑下面的代码声明和打字稿

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

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

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

+7

注:这已经被固定(不知道其确切TS版本)。我在VS中得到这些错误,就像你期望的那样: '索引签名是不兼容的。' '类型'{firstName:string; }'不能分配到类型'IPerson'。' '属性'姓氏'在类型'{firstName:string; }'。' – 2015-02-23 20:23:31

回答

156

编辑:这已被固定在最新的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 
+0

为什么你需要'id'符号?看起来没有必要。 – kiewic 2018-03-08 06:04:31

+0

使用'id'符号,您可以声明字典的键类型应该是什么。通过上面的声明,您不能执行以下操作:'persons [1] = {firstName:'F1',lastName:'L1'}' – thomaux 2018-03-08 08:09:49

43

我thomaux同意初始化类型检查错误是打字稿错误。但是,我仍然想要找到一种方法来在正确的类型检查中以单个语句声明和初始化Dictionary。此实现时间较长,但它增加了附加功能,如containsKey(key: string)remove(key: string)方法。我怀疑在0.9版本中可以使用泛型时可以简化它。

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

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 
+0

非常有帮助的示例代码。 “接口IDictionary”包含一个小错字,因为有对IPerson的引用。 – mgs 2013-04-09 05:31:09

+0

@mgs谢谢,我编辑了代码 – dmck 2013-04-09 13:25:08

+0

也很好实现元素计数 – nurettin 2014-11-11 18:05:47

2

如果你想忽略的属性,将其标记为可选加一个问号:

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

对于在打字稿中使用字典对象可以使用如下界面:

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

比选择的解决方案更好。 – Fl4v 2017-10-09 14:53:07