Объединение значений массива не работает должным образом - PullRequest
0 голосов
/ 25 марта 2020

Сегодня я работал над методом, который создает карту ключа-значения из двух списков строк. Вот пример:

const keys = ['a', 'b', 'c']
const values = ['x', 'y', 'z']
const map = createMap(keys, values)
/*
{
  a: 'x',
  b: 'y',
  c: 'z'
}
*/

Реализация, на которую я попал, выглядит так:

function createMap<T extends string>(
  keys: readonly T[],
  values: readonly string[]
): Record<T, string> {
  if (keys.length !== values.length) {
    throw new Error('Key and Value lists must have same length') 
  }

  return keys.reduce<Record<string, string>>((accumulator, key, index) => {
    if (accumulator.hasOwnProperty(key)) {
      throw new Error('Keys must be unique')
    }

    return {
      ...accumulator,
      [key]: values[index]
    }
  }, {})
}

И это работает, но вывод типа имеет странное свойство

Если параметр key представляет собой переменную, которая содержит массив строк, результатом будет: Record<string, string>, но если вы напрямую передадите массив параметру key, результатом будет: Record<'item1' | 'item2' | 'etc.', string>. Проверьте код ниже для получения более подробной информации:

const keys = ['a', 'b', 'c']
const values = ['x', 'y', 'z']
const map = createMap(keys, values) // type is Record<string, string>
const map = createMap(['a', 'b', 'c'], values) // type is Record<'a' | 'b' | 'c', string>

Может кто-нибудь объяснить, почему он так себя ведет?

Вот ссылка на этот код в TypeScript Playground

Ответы [ 2 ]

3 голосов
/ 25 марта 2020

Похоже, что тип литерала ['a', 'b', 'c'] выводится как тип кортежа ['a', 'b', 'c'], который при использовании в качестве массива становится Array<'a' | 'b' | 'c'>. Напротив, ваша переменная keys имеет тип Array<string>.

Обратный результат можно получить с помощью явных аннотаций типов:

const keys: ['a', 'b', 'c'] = ['a', 'b', 'c']
const values = ['x', 'y', 'z']

const m1 = createMap(keys, values) // => Record<'a' | 'b' | 'c', string>
const m2 = createMap(['a', 'b', 'c'] as string[], values) // => Record<string, string>
0 голосов
/ 25 марта 2020

В первом примере тип параметра keys имеет тип string[], и поэтому T имеет тип string, поэтому тип возвращаемого значения становится Record<string, string>.

Во втором примере Параметр keys - это кортеж строковых литералов.

Смотрите документы о кортежах здесь: https://www.typescriptlang.org/docs/handbook/basic-types.html#tuple.

Смотрите документы о строковых литералах здесь: https://www.typescriptlang.org/docs/handbook/advanced-types.html#string -literal-types

См. Пример ниже для более ясного представления о том, что происходит:

const keys: ['a', 'b', 'c'] = ['a', 'b', 'c']; // Type is tuple of string literal types
const map = createMap(keys, values) // type is Record<'a' | 'b' | 'c', string>
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...