Ввод для массива определенных значений, где каждое значение может появиться не более одного раза? (TypeScript)

#arrays #typescript #subset

#массивы #typescript #подмножество

Вопрос:

Допустим, у меня есть функция, подобная следующей:

 function getUserInfo(desiredProperties: ('name' | 'age' | 'salary')[]) {
  const userInfo: Record<string, unknown> = {};
  for (const propertyName of desiredProperties) {
    userInfo[propertyName] = fetchEffortfullyFromDatabase(...);
  }
  return userInfo;
}
  

Теперь, если я вызову функцию «нормально», скажем

 const userInfo = getUserInfo(['name', 'salary']);
  

все в порядке.
Но ничто не мешает вызвать такой

 const userInfo = getUserInfo(['name', 'name', 'name', ...]);
  

запуск множества ненужных обращений к базе данных. Конечно, это можно просто обработать во getUserInfo время выполнения, но я хочу, чтобы компилятор распознавал и запрещал такие вызовы.

Я мог бы перейти ('name' | 'age' | 'salary')[] на объединение всех возможных комбинаций имен свойств, т. Е. ['name'] | ['name', 'age'] | ['name', 'age', 'salary'] | ['age'] | ... , Но это слишком утомительно даже для трех значений и вряд ли выполнимо для большего количества (особенно с учетом порядка).

Итак, есть ли другой способ получить желаемый ввод? Может быть, что-то вроде AllCombinations<'name', 'age', 'salary'> ?

Ответ №1:

Вы можете использовать Set возможность ввода для извлечения только уникальных членов переданного аргумента:

 function getUserInfo(desiredProperties: ('name' | 'age' | 'salary')[]) {
  const uniqueMembers = new Set(desiredProperties); // this extract only unique members of array
  const userInfo: Record<string, unknown> = {};
  for (const propertyName of uniqueMembers) { // and here you iterate only through unique members
    userInfo[propertyName] = fetchEffortfullyFromDatabase(...);
  }
  return userInfo;
}

let userInfo = getUserInfo(['name', 'salary']);

userInfo = getUserInfo(['name', 'name', 'name']);
  

Конечно, такое решение не идеально, поскольку оно предполагает ненужные вычисления во время выполнения.

Если вы не хотите выполнять ненужные вычисления, вы можете установить тип desiredProperties as Set<'name' | 'age' | 'salary'> . А затем вызовите getUserInfo вот так:

 const userInfo = getUserInfo(new Set(['name', 'salary']));