如何为包含已知未知键的递归对象声明类型

how to declare types for recursive object which inclues known unknown keys

我想为这种递归对象声明类型,其中 namelink 是必填字段

{
          1: {
            name: 'Youtube',
            link: '/inventory/youtube',
            1: {
              name: 'home',
              link: '/inventory/youtube/home'
            }
          },
          2: {
            name: 'Network Infrastructure',
            link: '/inventory/network-infrastructure',
          }
} 

我试过这样做但出现错误(属性 'name' 类型 'string' 无法分配给 'string' 索引类型 'propTypes') ,

type propTypes = {
    name: string;
    link: string;
    [key: string | number]: propTypes
  }; 

如果未知键是任何可能的字符串,那么目前您想要的在 TypeScript 中是不可能的。

{[key: string]: PropTypes}这样的stringindex signature意味着:如果属性具有string类型的键存在,那么它的值必须是输入 PropTypes。但这意味着 linkname 属性也需要是 PropTypes 类型,而不是您想要的 string 类型。这就是错误的来源。

你可能想说“每个 string 除了 "link""name" 应该有一个 [=15= 类型的值]。但目前没有办法表达。在 microsoft/TypeScript#17867 有一个长期悬而未决的问题,要求这样的“混合”或“rest”索引签名。谁知道什么时候或是否会实施类似的东西。现在, TypeScript 中没有特定的类型可以这样工作。

有多种解决方法,但都有些复杂。请参阅 了解其中可能的不同方法的概述。


但是,在您的情况下,未知键似乎是 数字字符串 ,如 "1""2",而不是任意字符串。在这种情况下,您可以改用 number 索引签名:

type PropTypes = {
    name: string;
    link: string;
    [key: number]: PropTypes // okay
};

这没关系,因为 "name""link" 不是数字字符串。 namelink 属性应该有 string 值,而所有类似数字的属性应该有 PropTypes 值,这不再矛盾。因此你的递归对象符合这个定义:

const prop: { [key: number]: PropTypes } = {
    1: {
        name: 'Youtube',
        link: '/inventory/youtube',
        1: {
            name: 'home',
            link: '/inventory/youtube/home'
        },
        2: {
            name: 'explore',
            link: '/inventory/youtube/explore',
            1: {
                name: 'Indias Factory Customisation',
                link: '/inventory/youtube/Indias-first-Factory-Customisation'
            },
            2: {
                name: 'YouTube Mix',
                link: '/inventory/youtube/YouTube-Mix'
            }
        }
    },
    2: {
        name: 'Network Infrastructure',
        link: '/inventory/network-infrastructure',
    }
};

请注意 prop 不是 PropTypes 类型,因为它缺少 namelink 属性。但是由于每个 属性 和嵌套子 属性 确实 具有这些属性,您可以说 prop{[key: number]: PropTypes} 类型。

Playground link to code