我想存储字符串的映射 - >在Typescript对象中的字符串,并强制所有键映射到字符串。例如:
var stuff = {};
stuff["a"] = "foo"; // okay
stuff["b"] = "bar"; // okay
stuff["c"] = false; // ERROR! bool != string
我是否有办法强制执行值必须是字符串(或任何类型..)?
答案 0 :(得分:276)
var stuff: { [s: string]: string; } = {};
stuff['a'] = ''; // ok
stuff['a'] = 4; // error
// ... or, if you're using this a lot and don't want to type so much ...
interface StringMap { [s: string]: string; }
var stuff2: StringMap = { };
// same as above
答案 1 :(得分:69)
无论我走到哪里,我随身携带这个文件
export interface StringTMap<T> { [key: string]: T; };
export interface NumberTMap<T> { [key: number]: T; };
export interface StringAnyMap extends StringTMap<any> {};
export interface NumberAnyMap extends NumberTMap<any> {};
export interface StringStringMap extends StringTMap<string> {};
export interface NumberStringMap extends NumberTMap<string> {};
export interface StringNumberMap extends StringTMap<number> {};
export interface NumberNumberMap extends NumberTMap<number> {};
export interface StringBooleanMap extends StringTMap<boolean> {};
export interface NumberBooleanMap extends NumberTMap<boolean> {};
StringTMap
和NumberTMap
是泛型,可用于创建任何类型的地图(通过let myTypeMap: StringTMap<MyType> = {}
)。其余的是常见文字类型之间有用的预定义映射。
这里的重要语法是{ [key: string]: T; }
,表示接口强制使用类型为string
的键的对象文字(单词key
可以是任何标识符,应该用于指示密钥的重要性)和T
类型的值。如果你想构造一个string
&#34;名称&#34;对于密钥和boolean
值(并且不使用上面的继承),它的接口将是{ [name: string]: boolean }
。
10.10.2018更新:
查看下面的@dracstaxi答案 - 现在有一个内置类型Record
,它或多或少地完成了这个。
答案 2 :(得分:30)
快速更新:自Typescript 2.1起,内置了Record<T, K>
类型,其作用类似于字典。
文档示例:
// 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 Documentation on Record<T, K>
我在{[key: T]:K
上使用此键的唯一缺点是,您可以编码有用的信息,以了解要使用哪种键代替“键”,例如如果您的对象只有主键,则可以这样提示:{[prime: number]: yourType}
。
这是我写来帮助实现这些转换的正则表达式。这只会转换标签为“键”的情况。要转换其他标签,只需更改第一个捕获组:
查找:\{\s*\[(key)\s*(+\s*:\s*(\w+)\s*\]\s*:\s*([^\}]+?)\s*;?\s*\}
替换:Record<$2, $3>
答案 3 :(得分:7)
当我们写let a: { [s: string]: string; }
时,我们需要记住,在编写的打字稿之后,不是类型数据这样的东西,它只用于编译。并且{[s:string]:string;将编译为{}。
那就是说,即使你写了类似的东西:
class TrickyKey {}
let dict: {[key:TrickyKey]: string} = {}
这只是不会编译(即使是target es6
,你也会得到error TS1023: An index signature parameter type must be 'string' or 'number'.
所以实际上你只能使用字符串或数字作为潜在的密钥,所以这里没有那么强烈的类型检查意识,特别要记住,当js尝试按编号访问密钥时,它会将其转换为字符串。
因此,假设最佳做法是即使键是字符串也使用Map是非常安全的,所以我坚持:
let staff: Map<string, string> = new Map();
答案 4 :(得分:2)
您可以将名称传递给未知键,然后输入您的类型:
type StuffBody = {
[key: string]: string;
};
现在您可以在类型检查中使用它:
let stuff: StuffBody = {};
但是对于 FlowType ,不需要名称:
type StuffBody = {
[string]: string,
};
答案 5 :(得分:1)
在@ 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
代替type
定义。
答案 6 :(得分:0)
定义界面
interface Settings {
lang: 'en' | 'da';
welcome: boolean;
}
强制将键设置为“设置”界面的特定键
private setSettings(key: keyof Settings, value: any) {
// Update settings key
}
答案 7 :(得分:-1)
interface AccountSelectParams {
...
}
const params = { ... };
const tmpParams: { [key in keyof AccountSelectParams]: any } | undefined = {};
for (const key of Object.keys(params)) {
const customKey = (key as keyof typeof params);
if (key in params && params[customKey] && !this.state[customKey]) {
tmpParams[customKey] = params[customKey];
}
}
如果您对此概念有所了解,请发表评论