Typescript 具有联合类型的类型上不存在属性
我有一种类型试图描述一个可序列化的深嵌套“普通javascript”对象: 它允许我定义简单的深嵌套键-值对数字、字符串、布尔值或它们的数组:Typescript 具有联合类型的类型上不存在属性,typescript,Typescript,我有一种类型试图描述一个可序列化的深嵌套“普通javascript”对象: 它允许我定义简单的深嵌套键-值对数字、字符串、布尔值或它们的数组: const thing: MappingReferenceValues = { test: { test2: { test3: "hi", test4: 200, test5: [true, false] } } }; 太好了!声明它很好。它比任何都要好得多,因为它确保了我在那里没有函数,并且
const thing: MappingReferenceValues = {
test: {
test2: {
test3: "hi",
test4: 200,
test5: [true, false]
}
}
};
太好了!声明它很好。它比任何
都要好得多,因为它确保了我在那里没有函数,并且与未定义的
不同
然而,使用它确实很痛苦:
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
不存在于类型字符串上,但它存在于类型MappingReferenceValues
上。有没有办法避免再次将其强制转换为任何类型?此错误对您定义的接口有效
如果您收到MappingReferenceValues
类型的序列化值并对其进行反序列化,您如何知道该类型上存在test2
嵌套属性
在使用MappingReferenceValues
作为函数输入参数的示例中更符合逻辑:
函数解析(值:MappingReferenceValues){
值。/*我们不知道键,也不知道点后的类型*/
}
若您需要进一步操作刚刚创建的变量thing
,则省略类型定义。您仍然可以将其传递给需要MappingReferenceValues
类型的函数
函数解析(值:MappingReferenceValues){
/*待办事项*/
}
常数事物={
测试:{
测试2:{
测试3:“你好”,
测试4:200,
测试5:[对,错]
}
}
};
const output=thing.test.test2.test3;//工作
解析(事物);//也在工作;
此错误对您定义的接口有效
如果您收到MappingReferenceValues
类型的序列化值并对其进行反序列化,您如何知道该类型上存在test2
嵌套属性
在使用MappingReferenceValues
作为函数输入参数的示例中更符合逻辑:
函数解析(值:MappingReferenceValues){
值。/*我们不知道键,也不知道点后的类型*/
}
若您需要进一步操作刚刚创建的变量thing
,则省略类型定义。您仍然可以将其传递给需要MappingReferenceValues
类型的函数
函数解析(值:MappingReferenceValues){
/*待办事项*/
}
常数事物={
测试:{
测试2:{
测试3:“你好”,
测试4:200,
测试5:[对,错]
}
}
};
const output=thing.test.test2.test3;//工作
解析(事物);//也在工作;
您需要区分thing.test
和thing.newTest
根据MappingReferenceValues
的定义,thing可以包含任何字符串
键,因此所有这些访问都可以:
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;
}
您需要区分thing.test
和thing.newTest
根据MappingReferenceValues
的定义,thing可以包含任何字符串
键,因此所有这些访问都可以:
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;
}
这很有趣,因为你会说“你怎么知道它上面有test2嵌套属性?”但我同样会问,我怎么知道它上面有
test
属性?[key:string]
说明可以有任何字符串属性,但可能没有一个名为test
,甚至根本没有。这似乎前后矛盾。类似地,它假设它是一个字符串。所以我可以做事情。test.trim()
,即使它可能是嵌套对象。您定义了根对象上可以有任何名称的键。它可以是test
或,例如random
。尝试lineconst output=thing.random.test2.test3
,您将得到与test
属性完全相同的错误。这很有趣,因为您会说“您如何知道它上面有test2嵌套属性?”,但我同样可以问,我如何知道它上面有test
属性?[key:string]
说明可以有任何字符串属性,但可能没有一个名为test
,甚至根本没有。这似乎前后矛盾。类似地,它假设它是一个字符串。所以我可以做事情。test.trim()
,即使它可能是嵌套对象。您定义了根对象上可以有任何名称的键。它可以是test
或,例如random
。尝试lineconst output=thing.random.test2.test3
,您将得到与test
属性完全相同的错误。