ограничить дочерний ключ в объекте подтипом родительского ключа

#typescript

#typescript

Вопрос:

У меня есть куча правил, определенных как объект, со значениями, представляющими собой массив строк:

 const RULES = {
    Foo: ["Rule1", "Rule2"],
    Bar: ["Rule1"],
} as const
  

Я хотел бы использовать их RULES как способ определения другого объекта:

 const RELATIONS = {
    Foo: {
        Rule1: { newProp: "anyoldstringvalue" },
        Rule2: { newProp: "anynewstringvalue" }
    },
    Bar: {
        Rule1: { newProp: "anyoldstringvalue" }
    },
}
  

конечно, я ценю безопасность типов. Итак, я придумал:

 type mainRule = keyof typeof RULES // "Foo" | "Bar"
type subRules<T extends mainRule> = typeof RULES[T][number] // subRules<"Foo"> => "Rule1" | "Rule2"

type allRules = { [key in mainRule]: any }
type relation<T extends mainRule> = { [key in T]: { [key in subRules<T>]: { newProp: string } } }
  

Это может безопасно вводить проверку RELATIONS , RULES НО в подробном виде:

 const RELATIONS: allRules = {
  ...({
    Foo: {
      Rule1: { newProp: "anyoldstringvalue" },
      Rule2: { newProp: "anynewstringvalue" },
    },
  } as relation<"Foo">),
  ...({
    Bar: {
      Rule1: { newProp: "anyoldstringvalue" },
    },
  } as relation<"Bar">),
}
  

Этот способ гарантирует, что все основные правила присутствуют и что каждое подчиненное правило следует определению родительских правил. Это также гарантирует, что никакие ключи не могут быть повторены или пропущены… но я должен обязательно добавлять as relation<"desiredKey"> для каждого дочернего объекта. Кроме того, существует использование any , которое … по меньшей мере … нежелательно.

Ответ №1:

Похоже, вы добавили лишнюю вложенность.

 type relation<T extends mainRule> = { /* [key in T]: { */ [key in subRules<T>]: { newProp: string } }
  

Это работает для меня:

 type relation<T extends mainRule> = { [key in subRules<T>]: { newProp: string }}
type allRules = { [key in mainRule]: relation<key> }
  

Ссылка на игровую площадку

Комментарии:

1. Никогда не знал об использовании key в качестве последующего типа. Красиво, спасибо.