我想在Typescript对象中存储string ->字符串的映射,并强制所有值映射到字符串。例如:

var stuff = {};
stuff["a"] = "foo";   // okay
stuff["b"] = "bar";   // okay
stuff["c"] = false;   // ERROR!  bool != string

是否有一种方法让我强制值必须是字符串(或任何类型..)?


当前回答

一个快速更新:自Typescript 2.1以来,有一个内置的类型Record<T, K>,它的作用类似于字典。

在这种情况下,你可以这样声明:

var stuff: Record<string, any> = {};

你也可以通过联合文字类型来限制/指定潜在的键:

var stuff: Record<'a'|'b'|'c', string|boolean> = {};

下面是一个使用文档中的record类型的更通用的例子:

// For every properties K of type T, transform it to U
function mapObject<K extends string, T, U>(obj: Record<K, T>, f: (x: T) => U): Record<K, U>

const names = { foo: "hello", bar: "world", baz: "bye" };
const lengths = mapObject(names, s => s.length);  // { foo: number, bar: number, baz: number }

TypeScript 2.1文档记录<T, K>

我认为使用{[key: T]: K}的唯一缺点是,你可以编码关于你使用什么类型的键来代替“key”的有用信息,例如,如果你的对象只有质键,你可以这样提示:{[prime: number]: yourType}。

下面是我写的一个正则表达式来帮助这些转换。这只会转换标签为“key”的情况。要转换其他标签,只需更改第一个捕获组:

查找: \{\s*\[(key)\s*(+\s*:\s*(\w+)\s*\]\s*:\s*([^\}]+?)\s*;?\s*\}

替换:记录<$ 2,$ 3>

其他回答

定义接口

interface Settings {
  lang: 'en' | 'da';
  welcome: boolean;
}

强制键为设置界面的特定键

private setSettings(key: keyof Settings, value: any) {
   // Update settings key
}

实际上有一个内置的实用程序记录:

    const record: Record<string, string> = {};
    record['a'] = 'b';
    record[1] = 'c'; // leads to typescript error
    record['d'] = 1; // leads to typescript error

基于@shabunc的答案,这将允许将键或值(或两者都是)强制为您想强制的任何值。

type IdentifierKeys = 'my.valid.key.1' | 'my.valid.key.2';
type IdentifierValues = 'my.valid.value.1' | 'my.valid.value.2';

let stuff = new Map<IdentifierKeys, IdentifierValues>();

也应该使用enum而不是类型定义。

@Ryan Cavanaugh的回答完全没问题,而且仍然有效。值得补充的是,在16年秋季,当我们可以宣称ES6被大多数平台支持时,当你需要将一些数据与一些键关联时,几乎总是更好地坚持使用Map。

当我们写let a: {[s:字符串]:字符串;}我们需要记住typescript编译后没有类型数据这样的东西,它只用于编译。和{[s:字符串]:字符串;}将编译为{}。

也就是说,即使你写的是:

class TrickyKey  {}

let dict: {[key:TrickyKey]: string} = {}

这只是不会编译(即使对于目标es6,你也会得到错误TS1023:索引签名参数类型必须是'string'或'number'。

实际上,字符串或数字作为潜在的键是有限的,所以这里没有太多强制类型检查的意义,特别是要记住,当js试图通过数字访问key时,它会将其转换为字符串。

因此,假设最佳实践是使用Map,即使键是字符串,这是相当安全的,所以我坚持使用:

let staff: Map<string, string> = new Map();

你可以传递一个名字给未知键,然后写你的类型:

type StuffBody = {
  [key: string]: string;
};

现在你可以在你的类型检查中使用它:

let stuff: StuffBody = {};

但对于FlowType,不需要有名称:

type StuffBody = {
  [string]: string,
};