Создать объединение из значений вложенного объекта с разными ключами - PullRequest
3 голосов
/ 18 апреля 2020

Учитывая, что у меня есть следующее Options Тип

interface Options {
  parent1: {
    child1: {
      foo: 'bar'
    }
  };
  parent2: {
    child2: {
      baz: 'daz'
    }
  };
}

Как я могу превратить его в объединение всех значений дочерних свойств 2-го уровня, в данном случае

{ foo: 'bar' } | { baz: 'daz' }

I попробовал следующее

type KnownOptions = Options[keyof Options][keyof Options[keyof Options]];

Но это работает, только если дочерние свойства 2-го уровня одинаковы для всех свойств верхнего уровня. Например, это работает, когда я переименовываю child2 в `child1

Playground

Ответы [ 3 ]

4 голосов
/ 18 апреля 2020

Вы можете использовать сопоставленный тип для извлечения вложенного типа:

type KnownOptions<T> = T extends {
  [k in keyof T]: {
    [k: string]: infer OptionValue
  }
} ? OptionValue : never

// Good:
const a: KnownOptions<Options> = { foo: 'bar' }
const b: KnownOptions<Options> = { baz: 'daz' }

// Expect errors:
const c: KnownOptions<Options> = { foo: 'bad value' }
const d: KnownOptions<Options> = { badKey: 'bar' }

Playground

Это обобщенный тип c, который принимает тип, который имеет два уровня ключей. Условный тип (отмеченный троичным T extends Type ? A : B) говорит: «если обобщенный тип c является объектом, по крайней мере, на двух уровнях глубины, то возвращайте тип на каждом из этих вторых уровней. В противном случае возвращайте never тип, потому что тип generi c недопустим.

infer OptionalValue говорит: «какой бы тип здесь ни был, сохраните его как OptionValue». Затем он возвращается условным типом после того, как несколько типов имеют был сохранен в нем, создавая объединение каждого типа.

Я должен признать, я не совсем уверен, почему ключ первого уровня должен быть k in keyof T, но второй уровень может быть просто k: string Но это был единственный способ заставить его работать должным образом.

1 голос
/ 18 апреля 2020

Я бы написал KnownOptions так:

type KnownOptions = { [K in keyof Options]: Options[K][keyof Options[K]] }[keyof Options];

Здесь мы отображаем каждое свойство Options в объединение его свойств и затем объединение всех этих союзов вместе. Это может иметь больше смысла, если мы напишем его в терминах ValueOf<T>, определенных следующим образом:

type ValueOf<T> = T[keyof T];

type KO = ValueOf<{ [K in keyof Options]: ValueOf<Options[K]> }>;

Итак, ValueOf<T> дает вам объединение типов значений свойств объекта T (например, ValueOf<{a: string, b: number}> - это string | number), поэтому вы сопоставляете каждое свойство Options с ValueOf, а затем берете ValueOf все это.

You можете проверить, что каждое из этих определений оценивается как {foo: "bar";} | {baz: "daz";}, как требуется.


Хорошо, надеюсь, это поможет; удачи!

Детская площадка ссылка на код

0 голосов
/ 18 апреля 2020

Вы можете индексировать тип с помощью нотации ['propName'] для извлечения типа

type KnownOptions = Options['parent1']['child1'] | Options['parent2']['child2']

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...