联合类型的类型不存在该属性

时间:2019-08-21 07:50:01

标签: typescript

我有一个试图描述可序列化的深层嵌套“纯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类型上存在。有什么办法可以解决这个问题,而不仅仅是将其再次投放?

2 个答案:

答案 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.testthing.newTest

通过定义MappingReferenceValues,事物可以包含任何string键,因此所有这些访问都可以:

let test = thing.test;
let newTest = thing.newTest;
let newTest2 = thing.newTest2; // still 'newTest2' does't not exits on thing.

现在检查类型为testnewTestnewTest2。它们都可以是string | number | boolean | string[] | MappingReferenceValues | number[] | boolean[] | MappingReferenceValues[];

中的任何一个

因此,首先要像test.field那样访问其值,您需要将其类型缩小为MappingReferenceValues

可以使用

来缩小范围
function isMappingReferneceValues(a: unknown): a is MappingReferenceValues {
  ...
  return true;
}