yarkov
@yarkov
Проект "Жизнь после смерти" - lifeafterdeath.ru

Как типизировать аргумент функции в зависимости от другого аргумента?

Ссылка на пример: пример

Хочется избавиться от value: any в функции setProp.

import * as lodash from 'lodash';

/**
 * Тип позволяет получить ключи объекта вместе с вложенными.
 * Использование keyof IConfig позволит получить ключи только первого уровня.
 *
 * @example
 * interface IConfig {
 *   property: number
 *   nested: {
 *     nestedProp: number
 *   }
 * }
 *
 * // Тут автокомплит TS предложит использовать строки "property" и "nested"
 * const config: keyof IConfig = '';
 *
 * // А тут автокомплит TS предложит использовать строки "property", "nested" и "nested.nestedProp"
 * const nestedConfig: NestedKeyOf<IConfig> = '';
 */
type NestedKeyOf<ObjectType extends object> = {
  [Key in keyof ObjectType & (string | number)]: ObjectType[Key] extends object
    ? /**
       * Тип работает как надо. Это не костыль, а вынужденная мера.
       * TS считает что вложенность объекта может быть бесконечной,
       * но в текущей задаче там всего 2 уровня.
       */
      // @ts-ignore Просто верь мне ))
      `${Key}` | `${Key}.${NestedKeyOf<ObjectType[Key]>}`
    : `${Key}`;
}[keyof ObjectType & (string | number)];

interface IConfig {
  prop: number;
  nested: {
    nestedProp: string;
  };
}

const config: IConfig = {
  prop: 1,
  nested: {
    nestedProp: '2',
  },
};

// Здесь всё работает чётко
// NestedKeyOf справляется как надо
function getProp<T = any>(property: NestedKeyOf<IConfig>): T | null {
  return lodash.get(config, property) || null;
}

// Как типизировать "value" в зависимости от "property"
// Если property равен "prop", то тип value должен быть "number", так как typeof IConfig['prop'] === 'number'
// Если property равен "nested.nestedProp", то тип value должен быть "string", так как typeof IConfig['nested']['nestedProp'] === 'string'
function setProp(property: NestedKeyOf<IConfig>, value: any): void {
  lodash.set(config, property, value);
}

setProp('prop', 123);
setProp('nested.nestedProp', '123');

console.log(config);
console.log(getProp('nested.nestedProp'));
console.log(getProp('prop'));
  • Вопрос задан
  • 105 просмотров
Решения вопроса 1
WblCHA
@WblCHA
Примерно так:
https://www.typescriptlang.org/play?#code/JYWwDg9g...

Я учёл все (вроде) основные кейсы, остались только крайне редкие, которые почти никто никогда не использует. С ними работать тоже должно, но несовсем верно.
Ответ написан
Пригласить эксперта
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Войти через центр авторизации
Похожие вопросы