【问题标题】:Type for constant referencing its own values常量引用其自身值的类型
【发布时间】:2021-05-08 23:11:37
【问题描述】:

鉴于我有这个数组:

const rooms: Rooms = [
    {name: 'bathroom', neighboring: []},
    {name: 'kitchen', neighboring: ['living room']},
    {name: 'living room', neighboring: ['kitchen']},
] as const;

我想为Rooms 编写一个类型,它只允许neighboring 数组中的值也是name 属性的值。

我试过这样:

type Rooms = Array<{
    name: string,
    neighboring: RoomName[]
}>

type RoomName = typeof rooms[number]['name'];

不幸的是,这会导致 TypeScript 错误:

类型'readonly [{ readonly name: "bathroom";只读邻居:只读[]; }, ...]' 是 'readonly' 并且不能分配给可变类型 'Rooms'。

你有更好的主意吗?

【问题讨论】:

  • 您报告的错误与您在问题中提出的问题无关。从room 的定义中删除as const,错误消失。如果您需要将其声明为as const,则必须将Rooms 及其定义中涉及的所有类型设为只读。

标签: typescript


【解决方案1】:

您可以为房间数组使用泛型类型,并使用辅助函数从实际数组中推断类型参数。

这是使用来自this answerNoInfer 类型,因此房间名称是从name 属性中推断出来的,然后只在neighboring 属性中进行类型检查(所以如果你输入了错误的房间名称在neighboring,你会得到一个错误,这是可取的)。

type RoomsArray<K extends string> = Array<{name: K, neighboring: NoInfer<K>[]}>

function makeRooms<K extends string>(rooms: RoomsArray<K>): RoomsArray<K> {
    return rooms;
}

const rooms = makeRooms([
    {name: 'bathroom', neighboring: []},
    {name: 'kitchen', neighboring: ['living room']},
    {name: 'living room', neighboring: ['kitchen']},
]);

Playground Link

【讨论】:

    【解决方案2】:

    可以将房间名称提取成自己的类型吗?

    type RoomName = string;
    
    type Rooms = Array<{
        name: RoomName,
        neighboring: Array<RoomName>
    }>
    

    还可以将房间名称限制为特定的字符串:

    type RoomName = "bathroom" | "kitchen" | "living room";
    
    type Rooms = Array<{
        name: RoomName,
        neighboring: Array<RoomName>
    }>
    

    这是TS playground demo

    【讨论】:

    • 这是我目前正在做的一种解决方法,但我认为必须为每个房间名称定义两次很脏。
    • @user3817008 为什么要两次?
    • 是的,它只定义了一次?
    • @VLAZ 一次作为类型,一次在数组中作为值
    • @user3817008 那么您希望如何链接它们?如果没有 1. 命名事物 2. 说明链接指向的位置,您将无法做到这一点。不管你如何定义你需要至少两个引用的链接。除非您将它们定义为树形结构,但这也是限制性的,因为它不允许您将浴室连接到厨房,而厨房也连接到客厅。或类似的。您也不能直接与它建立循环链接。
    【解决方案3】:

    有(或应该有)一个简短且已知的房间类型列表。将它们放在enum 中,然后使用enum 定义更复杂的类型:

    enum RoomName { 
        bathroom = 'bathroom', 
        kitchen = 'kitchen',
        living = 'living room',
    };
    type Room = {
        name: RoomName,
        neighboring: RoomName[],
    };
    type Rooms = Room[];
    
    const rooms: Rooms = [
        { name: RoomName.bathroom, neighboring: [] },
        { name: RoomName.kitchen, neighboring: [RoomName.living] },
        { name: RoomName.living, neighboring: [RoomName.kitchen] },
    ];
    

    查看online

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2014-03-03
      • 2013-09-27
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多