我有一个试图描述可序列化的深层嵌套“纯javascript”对象的类型:
export interface MappingReferenceValues {
/** The reference values */
[key: string]:
| string
| number
| boolean
| MappingReferenceValues
| string[]
| number[]
| boolean[]
| MappingReferenceValues[];
}
它使我可以定义简单的深度嵌套键值对,包括数字,字符串,布尔值或它们的数组:
const thing: MappingReferenceValues = {
test: {
test2: {
test3: "hi",
test4: 200,
test5: [true, false]
}
}
};
太好了!很好地声明它。它比any
更好,因为它确保了我那里没有函数,而且与undefined
截然不同。
但是,使用它确实很痛苦:
const output = thing.test.test2.test3
出现错误:
Property 'test2' does not exist on type 'string | number | boolean | MappingReferenceValues | string[] | number[] | boolean[] | MappingReferenceValues[]'.
Property 'test2' does not exist on type 'string'.
test2
在string类型上不存在,但在MappingReferenceValues
类型上存在。有什么办法可以解决这个问题,而不仅仅是将其再次投放?
答案 0 :(得分:1)
此错误对您定义的接口有效。
如果您收到MappingReferenceValues
类型的序列化值并反序列化,您如何知道上面有test2
嵌套属性?
在使用MappingReferenceValues
作为函数的输入参数的示例中更合乎逻辑:
function parse(value: MappingReferenceValues) {
value./* We don't know keys, nor types after the dot */
}
如果您需要操作刚刚创建的变量thing
,请忽略类型定义。您仍然可以将其传递给需要MappingReferenceValues
类型的函数。
function parse(value: MappingReferenceValues) {
/* TODO */
}
const thing = {
test: {
test2: {
test3: "hi",
test4: 200,
test5: [true, false]
}
}
};
const output = thing.test.test2.test3; // working
parse(thing); // also working;
答案 1 :(得分:1)
const thing: MappingReferenceValues = {
test: {
test2: {
test3: "hi",
test4: 200,
test5: [true, false]
}
},
newTest: [2]
};
您需要区分thing.test
和thing.newTest
。
通过定义MappingReferenceValues
,事物可以包含任何string
键,因此所有这些访问都可以:
let test = thing.test;
let newTest = thing.newTest;
let newTest2 = thing.newTest2; // still 'newTest2' does't not exits on thing.
现在检查类型为test
,newTest
,newTest2
。它们都可以是string | number | boolean | string[] | MappingReferenceValues | number[] | boolean[] | MappingReferenceValues[]
;
因此,首先要像test.field
那样访问其值,您需要将其类型缩小为MappingReferenceValues
。
可以使用
来缩小范围function isMappingReferneceValues(a: unknown): a is MappingReferenceValues {
...
return true;
}