Общая функция машинописного текста для динамического ключа и значения

const arrayToObject = <T>(array: T[], key: keyof T): Record<string, T> => {
  return array.reduce(
    (accumulator: Record<string, T>, currentValue: T) =>
      Object.assign(accumulator, {
        [(currentValue[key] as string).toString()]: currentValue,
      }),
    {} as Record<string, T>
  );
};

Можно ли вообще избежать использования «как строки»? как я могу проверить тип, что значение свойства «ключ» в типе T всегда является строкой?

type T {
    someOtherProperty: 20,
    active: false,
   [key]: string; (the value type of the property "key" must be string)
}
Принципы SOLID в JavaScript с примерами
Принципы SOLID в JavaScript с примерами
Принцип единой ответственности подразумевает то, что:
Типы привязки данных в Angular
Типы привязки данных в Angular
Привязка данных автоматически поддерживает страницу в актуальном состоянии на основе состояния вашего приложения. Вы используете привязку данных,...
3 паттерна TypeScript, которые я использую в своей повседневной работе
3 паттерна TypeScript, которые я использую в своей повседневной работе
В TypeScript 2.0 в язык был добавлен модификатор readonly.
Мифический Angular - Миф Angular: стили компонентов
Мифический Angular - Миф Angular: стили компонентов
Это очень короткая и интересная для меня тема. В Angular каждый компонент может иметь свои собственные прикрепленные стили. Стили могут находиться в...
Подсказка RxJS [filter, skipWhile]
Подсказка RxJS [filter, skipWhile]
Эта подсказка описывает разницу между операторами filter и skipWhile из библиотеки RxJS .
Шаблоны Angular PrimeNg
Шаблоны Angular PrimeNg
Как привнести проверку типов в наши шаблоны Angular, использующие компоненты библиотеки PrimeNg, и настроить их отображение с помощью встроенной...
1
0
53
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Это будет делать:

const arrayToObject = <T extends Record<any, string>>(array: T[], key: keyof T): Record<string, T> => {
  return array.reduce(
    (accumulator: Record<string, T>, currentValue: T) =>
      Object.assign(accumulator, {
        [currentValue[key].toString()]: currentValue,
      }),
    {}
  );
};

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

Привет, я забыл упомянуть, что есть другие свойства, которые не являются строковым типом, я только специально хочу, чтобы свойство «ключ» было строковым типом.

Lucas Chan 13.02.2023 01:08
Ответ принят как подходящий

Вы можете сделать arrayToObject() универсальным как для типа элемента массива T, так и для соответствующего типа ключа K, и ограничить T так, чтобы его свойство по ключу K можно было присвоить string:

const arrayToObject = <T extends Record<K, string>, K extends keyof T>(
  array: T[], key: K
): Record<string, T> => {
  return array.reduce<Record<string, T>>(
    (accumulator, currentValue) =>
      Object.assign(accumulator, {
        [currentValue[key]]: currentValue,
      }),
    {}
  );
};

Это компилируется без ошибок, и вы можете проверить, что это работает:

interface Foo {
  x: number,
  y: string,
  z: boolean
}

const foos: Foo[] = [
  { x: 1, y: "a", z: true }, 
  { x: 2, y: "b", z: false }, 
  { x: 3, y: "c", z: true }
];

const obj = arrayToObject(foos, "y"); // okay

Object.entries(obj).forEach(
  ([k, v]) => console.info(k, v.x.toFixed(1), v.y.toUpperCase())
);
/* "a",  "1.0",  "A" 
   "b",  "2.0",  "B" 
   "c",  "3.0",  "C" */ 

arrayToObject(foos, "x") // error!
// ---------> ~~~~
// Types of property 'x' are incompatible.

Выглядит неплохо. Компилятор примет правильный вызов, но пожалуется, если вы передадите ему неправильный ключ (хотя он скажет, что это неправильный массив, так как он использует ключ для проверки типа элемента массива, а не наоборот... но ошибка ясна, foos' элементы не имеют string-значного x свойства).

Площадка ссылка на код

Другие вопросы по теме