我想在Typescript对象中存储string ->字符串的映射,并强制所有值映射到字符串。例如:
var stuff = {};
stuff["a"] = "foo"; // okay
stuff["b"] = "bar"; // okay
stuff["c"] = false; // ERROR! bool != string
是否有一种方法让我强制值必须是字符串(或任何类型..)?
我想在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,
};