位置树对象类型声明

3
我有一个代表位置树的对象。每个位置可能有子位置(或没有),并且有一个数字ID。
{
    id: 0,
    USA: {
        id: 1,
        ARIZONA: {
            id: 2,
            PHOENIX: {
                id: 3
            },
            TUSCANY: {
                id: 4
            }
        },
        ALABAMA: {
            id: 4,

        }
    },
    CANADA: {
        id: 6,
        ONTARIO: {
            id: 7,
            TORONTO: {
                id: 8
            },
            OTTAWA: {
                id: 9
            }
        },
        QUEBEC: {
            id: 10,
            MONTREAL: {
                id: 11
            }
        },
    }
    UK: {
        id: 12,
        LONDON: {
            id: 13
        }
    }
}

我正在尝试将其表示为接口

interface Location  {
    id: number;
    [key in string]?:  Location

}

但它不让我这么说:

一个映射类型不能声明属性或方法。ts(7061) 我也试过了。

interface Location  {
    id: number;
    [key:string]:  Location

}

但它显示:

属性 id 的类型为数字,无法分配给字符串索引类型 Location


创建这个类型将非常棘手。你是否愿意更改数据模型? - Alex Wayne
2个回答

2

您可以使用type代替interface来实现此功能。我们会使用type,因为这样我们就可以使用交集和联合类型。我们将像下面这样使用它:

type Foo = { id: number } | { id: number } & { [key: string]: Foo };

Foo可以是一个带有id属性的对象,也可以是带有id属性和更多Foo对象的字符串索引签名。

如果你想要在索引访问时得到Foo | undefined类型的结果,可以使用noUncheckedIndexAccess编译选项(虽然比较严格),或者把索引签名中的Foo替换成像Foo | undefined这样的内容。

示例


2
type Idable = { id: number }

type IndexableLocation = { [key: string]: SomeLocation }

type SomeLocation = Idable | (Idable & IndexableLocation)

说明

const locations: SomeLocation = {
  id: 0,
  USA: {
    id: 1,
    ARIZONA: {
      id: 2,
      PHOENIX: {
        id: 3
      },
      TUSCANY: {
        id: 4
      }
    },
    ALABAMA: {
      id: 4,

    }
  },
  CANADA: {
    id: 6,
    ONTARIO: {
      id: 7,
      TORONTO: {
        id: 8
      },
      OTTAWA: {
        id: 9
      }
    },
    QUEBEC: {
      id: 10,
      MONTREAL: {
        id: 11
      }
    },
  },
  UK: {
    id: 12,
    LONDON: {
      id: 13
    }
  }
};

console.log((locations as IndexableLocation)["USA"]); // Type Asserion is important ere to satisfy the compiler

console.log(locations.id);

这不就是我的答案吗,只不过将Foo中的类型移入别名中,并重命名了Foo。 - zenly
我已经将你的答案标记为有用。当我们通过类型访问字段时,我还包括了一个错误。相信我,我们俩在这方面都有相同的想法。@youdateme。 - Nalin Ranjan
好的,我的错,我太匆忙了,这实际上是一个相当琐碎的问题。 - zenly

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接