TypeScript - преобразование типа: {ключ: Kn, значение: Vn} [] -> {[ключ: Kn]: Vn} - PullRequest
1 голос
/ 02 мая 2020

Я хочу написать функцию, которая принимает кортежи следующего типа / структуры:

type Input = [
  { key: K1, value: V1 },
  { key: K2, value: V2 },
  { key: K3, value: V3 },
  // ...
  { key: KN, value: VN }
]

и выводит следующий тип:

type Output = {
  [key: K1]: V1,
  [key: K2]: V2,
  [key: K3]: V3,
  // ...
  [key: KN]: VN
}

Примерно так:

function fromArray(xs: Input): Output {
  const obj = {} as Output
  for (const x of xs) {
    obj[x.key] = x.value
  }
  return obj
}

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

const geometry = fromArray([
  { key: 'circle',    value: { color: 'blue', radius: 3 } },
  { key: 'rectangle', value: { color: 'red', width: 3, height: 2 } },
  { key: 'line',      value: { length: 5 } }
])

// Now, I essentially want autocomplete on the following:
geometry.circle.color  // type = string
geometry.line.length   // type = number

Возможно ли это в текущей версии TypeScript?

I не обращайте внимания на сигнатуру типа fromArray, выглядящую беспорядочно .

Ответы [ 2 ]

2 голосов
/ 02 мая 2020

Я думаю, я бы написал так ... учитывая KV, тип объекта ключ / значение c, передаваемый как элемент xs аргумента fromArray() (или объединение таких типов), тип KeyValToObj<T>, соответствующий типу выходного объекта:

type KeyValToObj<KV extends { key: PropertyKey, value: any }> =
  { [K in KV['key']]: Extract<KV, { key: K }>['value'] };

Вы можете видеть, что если KV является объединением, подобным {key: "a", value: string} | {key: "b", value: number}, тогда KeyValToObj<KV> будет иметь ключ K для каждого key свойства в KV, и значением будет соответствующее value свойство члена KV с key типа K: {a: string; b: number}.

Тогда я бы дал fromArray() следующую подпись:

function fromArray<XS extends Array<{ key: K, value: any }>, K extends PropertyKey>(
  xs: XS | []): KeyValToObj<XS[number]> {
  const obj = {} as any;
  for (const x of xs) {
    obj[x.key] = x.value
  }
  return obj
}

С xs входом типа XS мы выводим KeyValToObj<XS[number]>, тип объекта, соответствующий объединению элементов типы XS. Нам нужно утверждение типа от до any, чтобы реализация не жаловалась; компилятор не сможет проверить, что мы действительно возвращаем правильный тип вывода здесь, поэтому я не стал пытаться.

Есть несколько складок в этой сигнатуре, чтобы сделать вывод типа работающим так, как я want: тип K кажется излишним (почему бы не заменить его на PropertyKey?), но это подсказка, чтобы заставить компилятор выводить строковых литералов типов для свойств key. И | [] кажется излишним (зачем явно разрешать пустой кортеж, когда это может быть XS?), Но это подсказка компилятору для вывода типа кортежа вместо XS неупорядоченного массива ... что само по себе кажется странным (почему мы заботимся о порядке XS, когда мы используем только XS[number], тип элемента?), но является подсказкой для предотвращения нормализации компилятором типы элементов содержат все свойства. Если вы ослабите любое из этих ограничений, вы получите странное поведение вывода.


Хорошо, давайте попробуем:

const geometry = fromArray([
  { key: 'circle', value: { color: 'blue', radius: 3 } },
  { key: 'rectangle', value: { color: 'red', width: 3, height: 2 } },
  { key: 'line', value: { length: 5 } }
])

geometry.circle
// circle: { color: string; radius: number; } 
geometry.circle.radius; 

geometry.line
// line: { length: number; }
geometry.line.length;

geometry.rectangle
// rectangle: { color: string; width: number; height: number; }
geometry.rectangle.width;

Выглядит хорошо. Вы получаете все автозаполнения, которые вы хотели. Для чего стоит, если вы используете дубликат ключа, тип вывода имеет объединение соответствующих типов значений в этом ключе.


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

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

0 голосов
/ 02 мая 2020

Это один из подходов, который обеспечивает некоторую безопасность типов, но, к сожалению, все же может допускать несколько ложных срабатываний. Любой ключ допустим с любым значением, , но , по крайней мере, он подтверждает, что это действительный ключ и значение.

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