在Typescript中声明并初始化Dictionary

给定以下代码

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


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

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

694018 次浏览

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

注意:这已经被修复(不确定确切的TS版本)。我 在VS中获取这些错误,正如你所期望的 不相容的。类型'{firstName:字符串;}'不能赋值给类型 “IPerson”。属性“lastName”在类型中缺失 字符串;}”。< /代码> < / p >
人力资源> < p > < 显然,当在声明时传递初始数据时,这不起作用。 我猜这是TypeScript中的一个bug,所以你应该在项目站点上提出一个

你可以通过在声明和初始化中分割你的例子来使用类型化字典,比如:

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

我同意thomaux的说法,初始化类型检查错误是TypeScript的一个bug。但是,我仍然想找到一种方法,通过正确的类型检查在单个语句中声明和初始化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

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

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

要在typescript中使用字典对象,可以使用interface,如下所示:

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

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

Typescript在你的例子中失败了,因为它期望所有字段都出现。使用记录和部分实用程序类型来解决它。

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. 记录类型创建一个字典/hashmap。
  2. 部分类型表示某些字段可能缺失。

备用。

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

lastName?: string;

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

如果你正在寻找一个简单的方法来创建一个字典,即使在typescript中,它是使用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

Record< Tkey Tobject>有点像c#字典

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


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


//Remove
delete myRecord[”key1"];


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