与C#中一样,将TypeScript对象作为字典类型


335

我有一些使用对象作为字典的JavaScript代码。例如,“个人”对象将保留从电子邮件地址键入的一些个人详细信息。

var people = {<email> : <'some personal data'>};

adding   > "people[<email>] = <data>;" 
getting  > "var data = people[<email>];" 
deleting > "delete people[<email>];"

可以在Typescript中描述吗?还是我必须使用数组?


5
老的文章,但请注意,还有就是ES6地图
老白德曼灰色

Answers:


546

在较新版本的打字稿中,您可以使用:

type Customers = Record<string, Customer>

在旧版本中,您可以使用:

var map: { [email: string]: Customer; } = { };
map['foo@gmail.com'] = new Customer(); // OK
map[14] = new Customer(); // Not OK, 14 is not a string
map['bar@hotmail.com'] = 'x'; // Not OK, 'x' is not a customer

如果您不想每次都键入整个类型注释,也可以创建一个接口:

interface StringToCustomerMap {
    [email: string]: Customer;
}

var map: StringToCustomerMap = { };
// Equivalent to first line of above

2
这是确保编译器将索引限制为字符串的一种有用方法。有趣。看起来您不能将索引类型指定为字符串或整数以外的任何其他类型,但这很有意义,因为它仅映射到本机JS对象索引。
肯·史密斯

5
您可能知道这一点,但是这种方法也存在一些潜在的难题,最大的缺点是没有一种安全,简便的方法来遍历所有成员。例如,此代码显示map包含两个成员:(<any> Object.prototype).something = function(){}; Customer {}类var map:{[email:string]:Customer;} = {}; map ['foo@gmail.com'] =新的Customer(); for(var i in map){console.log(map [i])}
肯·史密斯

5
如何从中删除?
TDaver

24
另一个有趣的方法是:接口MapStringTo <T> {[key:string]:T; }然后声明变量,例如var map:MapStringTo<Customer> = {};
orellabac

1
请注意,索引约束不再起作用。阅读更多。
大卫·谢里

127

除了使用MAP- 喜欢的对象,出现了一个实际的Map对象有一段时间了,对编译器ES6时,或者使用与ES6一个填充工具时,这是打字稿可用类型的定义

let people = new Map<string, Person>();

它支持与相同的功能Object,但语法稍有不同:

// Adding an item (a key-value pair):
people.set("John", { firstName: "John", lastName: "Doe" });

// Checking for the presence of a key:
people.has("John"); // true

// Retrieving a value by a key:
people.get("John").lastName; // "Doe"

// Deleting an item by a key:
people.delete("John");

与使用类似地图的对象相比,仅此一项就具有多个优点,例如:

  • 支持基于非字符串的键,例如数字或对象,都不支持Object(不,Object不支持数字,它将数字转换为字符串)
  • 不使用时出现错误的可能性较小--noImplicitAny,因为Map始终具有类型和类型,而对象可能没有索引签名
  • 添加/删除项(键值对)的功能针对该任务进行了优化,与在Object

此外,Map对象为常见任务提供了更强大,更优雅的API,Object如果不将辅助函数合并在一起,则大多数对象都无法通过simple来使用(尽管其中一些需要针对ES5目标或更低版本的完整ES6迭代器/可迭代polyfill):

// Iterate over Map entries:
people.forEach((person, key) => ...);

// Clear the Map:
people.clear();

// Get Map size:
people.size;

// Extract keys into array (in insertion order):
let keys = Array.from(people.keys());

// Extract values into array (in insertion order):
let values = Array.from(people.values());

2
棒极了!但是遗憾的是,它使用序列化了错误JSON.stringify(),因此可以用于例如socket.io :(
Lion

@Lion-好吧,Map序列化很有趣。我首先进行序列化之前先转换为键-值对对象,然后再转换(例如的对象{ key: "John", value: { firstName: "John" } })。
约翰·威兹

2
我犯了一个错误,使用地图而不是普通的旧对象,而序列化确实让我受益。在我看来,请避开。
user378380 '19

1
这很漂亮。很高兴您启发了我终于涉足地图。这几乎可以代替我通常的键盘映射/字典结构,因为强键入密钥要容易得多。
Methodician

77

您可以使用以下模板化接口:

interface Map<T> {
    [K: string]: T;
}

let dict: Map<number> = {};
dict["one"] = 1;

7
请注意,这与es6 Map类型冲突。比其他答案更好,因为索引约束被忽略。
老巴德曼·格雷(Badman Gray),

如何检查字典中是否存在键?
samneric

dict.hasOwnProperty('key')
Dimitar Mazhlekov

1
我使用Dictionary而不是Map以避免混淆,并且您可以使用文字对象表示法:let dict: Dictionary<number> = { "one": 1, "two": 2 };
PhiLho

8

您还可以在typescript中使用Record类型:

export interface nameInterface { 
    propName : Record<string, otherComplexInterface> 
}

5

Lodash具有简单的Dictionary实现并具有良好的TypeScript支持

安装Lodash:

npm install lodash @types/lodash --save

导入和用法:

import { Dictionary } from "lodash";
let properties : Dictionary<string> = {
    "key": "value"        
}
console.log(properties["key"])

3

您可以Record为此使用:

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

示例(AppointmentStatus枚举和一些元数据之间的映射):

  const iconMapping: Record<AppointmentStatus, Icon> = {
    [AppointmentStatus.Failed]: { Name: 'calendar times', Color: 'red' },
    [AppointmentStatus.Canceled]: { Name: 'calendar times outline', Color: 'red' },
    [AppointmentStatus.Confirmed]: { Name: 'calendar check outline', Color: 'green' },
    [AppointmentStatus.Requested]: { Name: 'calendar alternate outline', Color: 'orange' },
    [AppointmentStatus.None]: { Name: 'calendar outline', Color: 'blue' }
  }

现在将接口作为值:

interface Icon { Name: string Color: string }

用法:

const icon: SemanticIcon = iconMapping[appointment.Status]


这是非常有用的。你会使用字符串enumclass/objectAppointmentStatus-或者什么关系呢?
德莱奈

对我来说,这是一个枚举。看到我更新的答案。
Nick N.

@Drenai没关系,这就是您想要的
Nick N.

-2

有一个库提供打字稿中的强类型可查询集合

集合是:

  • 清单
  • 字典

该库称为ts-generic-collections。(GitHub上的源代码

您可以创建字典并按以下方式查询它:

  it('firstOrDefault', () => {
    let dictionary = new Dictionary<Car, IList<Feature>>();

    let car = new Car(1, "Mercedez", "S 400", Country.Germany);
    let car2 = new Car(2, "Mercedez", "S 500", Country.Germany);

    let features = new List<Feature>();

    let feature = new Feature(1, "2 - Door Sedan");
    features.add(feature);

    dictionary.add(car, features);

    features = new List<Feature>();
    feature = new Feature(2, "4 - Door Sedan");
    features.add(feature);

    dictionary.add(car2, features);

    //query
    let first = dictionary.firstOrDefault(x => x.key.name == "Mercedez");

    expect(first.key.id = 1);
  });
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.