JSON String {String: String[]}的最佳Typescript类型



我有一个JSON文件,我想在typescript中使用,但不太确定如何定义类型/接口。

它基本上定义了虚拟键盘的布局。所以它会有一个layoutName,然后每行都有一个名字。

布局名称(如"default", "emoji")我想成为一个通用的字符串,可以是任何值,所以我在考虑记录类型。行名应该是一致的,但他们必须动态访问,所以我认为他们应该是记录了吗?

下面是JSON文件中的一个示例:

{
"default": {
"row1": [
"1",
"2",
"3",
"4",
"5",
"6",
"7",
"8",
"9",
"0",
"-",
"=",
"Backspace"
],
"row1_shift": [
"!",
"@",
"#",
"$",
"%",
"^",
"&",
"*",
"(",
")",
"_",
"+",
"Backspace"
],
},
"emoji": {
"row1" : []
}

谢谢

所以我认为您确实希望对接口的顶级密钥使用string索引签名。但是,对于下一个级别,如果您有一组已知的键,您可能应该使用它们,即使您必须动态访问属性。例如:

type RowNames = `row${1 | 2 | 3 | 4 | 5}${"" | "_shift"}`;
interface VirtualKeyboard {
[layoutName: string]: Partial<Record<RowNames, string[]>>;
}

相当于

/* type VirtualKeyboard = {
[x: string]: {
row1?: string[] | undefined;
row1_shift?: string[] | undefined;
row2?: string[] | undefined;
row2_shift?: string[] | undefined;
row3?: string[] | undefined;
row3_shift?: string[] | undefined;
row4?: string[] | undefined;
row4_shift?: string[] | undefined;
row5?: string[] | undefined;
row5_shift?: string[] | undefined;
};
} */

我只是使用模板文字类型来简洁地表达RowNames,使用Partial<T>Record<K, V>实用程序类型来表达子属性类型,而不重复。但这是一样的。


然后,当涉及到读取属性时,您可以这样做:

const virtualKeyboard: VirtualKeyboard = {/*...*/}
for (const layout in virtualKeyboard) {
for (const index of [1, 2, 3, 4, 5] as const) {
for (const modifier of ["", "_shift"] as const) {
let currentRow = virtualKeyboard[layout][`row${index}${modifier}`];
if (!currentRow) continue;
for (const key of currentRow) {
console.log(key.toUpperCase());
}
}
}
}

第一个循环遍历virtualKeyboard的所有键。密钥layout的类型是string,使用它可以索引到virtualKeyboard,因为它具有string索引签名。对于下一个循环,我使用const断言的索引和修饰符数组,以便编译器知道它们分别是1 | 2 | 3 | 4 | 5"" | "_shift"类型。

此时,您可以使用实际的模板文字`row${index}${modifier}`来索引virtualKeyboard[layout]。编译器能够将其视为模板文字类型(由于TS 4.3中的改进;在此之前,您可能还需要as const),因此它会看到该键是子属性的已知键之一。

这意味着它知道currentRow的类型是string[] | undefined(由于定义中的Partial<>,它可能是undefined)。如果您知道它永远不会是undefined,那么您可以省略Partial<>)。因此,一旦我们检查了undefined,我们就可以遍历它,编译器期望每个key都是string

Playground链接到代码

相关内容

  • 没有找到相关文章

最新更新