Определить тип возвращаемоего значения функции, в зависимости от переданного параметра

Рейтинг: 0Ответов: 1Опубликовано: 05.04.2023

У меня есть тип:

type TaskType = "return professions";

И есть описанная функция в интерфейсе:

interface IInterfaceName
{
    getReponse(message: string, task?: TaskType): string | string[];
}

Моя задача, чтобы функция возвращала не string | string[], а более известный тип. Для текущей задачи, если мы передаем в taks значение "return professions", функция должна вернуть string, если же я передам undefined (или же вызову функцию без передачи параметра), я хочу получить тип string.

Я слышал про infer, возможно оно окажется решением. Но я не пойму как это написать.


getResponse("test") // return type: string
getResponse("test", "return professions") // return type: string[]

Ответы

▲ 1Принят

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

В конкретном примере просто перегружается сигнатура, TS сам определит к чему больше подходят аргументы.

type TaskType = "return professions";

interface IInterfaceName
{
    getReponse(message: string): string;
    getReponse(message: string, task: TaskType): string[];
    getReponse(message: string, task?: TaskType): string | string[];
}

UPD1: Еще примеры:

type TaskType = "a" | "b" 

type TaskTypeObj = {
  type: "a" | "b"
}

type TaskTypeReturns = {
  a: string
  b: string[]
}

interface IInterfaceName
{
    getReponse<T extends (TaskType | undefined)>(message: string, task?: T): T extends undefined ? 123 : (T extends TaskType ? TaskTypeReturns[T] : never);
}

// Для извлечения типа определенного свойства
interface IInterfaceNameV2
{
    getReponse<T extends TaskTypeObj>(message: string, task?: T): T extends {type: infer V} ? (V extends TaskType ? TaskTypeReturns[V] : never) : never;
}

function foo(name: IInterfaceName) {
  const res1 = name.getReponse("xxx", 'a'); // string
  const res2 = name.getReponse("xxx", 'b'); // string[]
  // Обрати внимание, что без перегрузки мы получили не то что ожидаем - а вообще все типы
  const res3 = name.getReponse("xxx"); // string | string[] | 123
}

function fooV2(name: IInterfaceNameV2) {
  const res1 = name.getReponse("xxx", {type: 'a'}); // string
  const res2 = name.getReponse("xxx", {type: 'b'}); // string[]
  const res3 = name.getReponse("xxx"); // string | string[]
}

typescriptlang.org play

UPD2: Смотри еще