Анонсировали на днях Typescript 5.8, в котором добавили фичу для контроля в функциях, которые должны возвращать разные типы, в зависимости от входных параметров.

Допустим, у нас есть два типа объектов, например, два варианта одного и того же запроса на сервер:

interface Index {
  index: number;
}

interface Para {
  para: number;
}

type Requests = Index | Para;

И, в зависимости от того, какой отправлен запрос, должен вернуться один из двух ответов:

interface IndexResponse {
  index: number;
}

interface ParasResponse {
  paras: number[];
}

Оно и раньше было можно описать выбор типа результата в зависимости от типа входного параметра, но начиная с Typescript 5.8 больше не нужно писать преобразования через as Responses<T> в функции-обработчике и терять контроль над типами:

type Responses<T extends Requests> =
  T extends Index ? IndexResponse :
  T extends Para ? ParasResponse :
  never; // в дженерике обязательно должна быть "аварийная" ветка с `never`

function request<T extends Requests>(req: T): Responses<T> {
  if ('index' in req) {
    return { index: 11 } // больше не нужен: as Responses<T>
  }

  return { paras: [1, 2, 3] } // больше не нужен: as Responses<T>
}

// call Index:
const index = request({ index: 22 });

// call Paras
const paras = request({ para: 11 });

Ссылка на playground.