Как в TS получить тип, возвращаемого функцией результата?

Функция runAgents принимает дикт с классом, у которого есть метод parse()
и возвращяет дикт с результатами работы функции.

Как объявить тип результата (IAgentsResult) функции runAgents что бы TS сам подставлял правильные типы в зависимости от входного типа?

export interface IAgentList {[key: string]: IAgentBase<any>}

export interface IAgents extends IAgentList {
    items?: IItemsParser;
    page?: IPageParser;
    parser?: IWebParser;
}

export interface IAgentBase<T> {
    parse(): Promise<T>;
}

export interface IItemsParser extends IAgentBase<IItem[]> {
}

export interface IPageParser extends IAgentBase<IDataSet[]> {
}

export interface IWebParser extends IAgentBase<any> {
}

export interface IAgentsResult<T> {
    items?: IItem[];
    page?: IDataSet[];
    parser?: any;
}

// в реальности все иначе, написал для понимания желаемого результата
async function runAgents<T extends IAgentList>(agents: IAgentList): Promise<IAgentsResult<T>> {
    const result: IAgentsResult<T> = {};
    Object.keys(agents).forEach(
      async key => result[key] = await agents[key].parse()
    );
    return result;
}

const agents : IAgents = {...}
const result = runAgents(agents)
  • Вопрос задан
  • 761 просмотр
Решения вопроса 1
@Interface
Если я все правильно понял то сигнатура runAgents должна стать чем-то вроде:
async function runAgents<T extends IAgentList>(agents: T): Promise<ResolveResult<T>>

где ResolveResult:
type ResolveResult<T extends IAgentList> = {
    [key in keyof T]: T[key] extends IAgentBase<infer R> ? R : never;
}


Решение основанно на infer из TS 2.8: https://www.typescriptlang.org/docs/handbook/relea...

Весь код (слегка измененный):
spoiler
type IItem = {type: 'IItem'};
type IDataSet = {type: 'IDataSet'};
export type IAgentList = {
    [key: string]: IAgentBase<any>;
}

export interface IAgents extends IAgentList {
    items: IItemsParser;
    page: IPageParser;
    parser: IWebParser;
}

export interface IAgentBase<T> {
    parse(): Promise<T>;
}

export interface IItemsParser extends IAgentBase<IItem[]> {
}

export interface IPageParser extends IAgentBase<IDataSet[]> {
}

export interface IWebParser extends IAgentBase<any> {
}

export interface IAgentsResult<T> {
    items?: IItem[];
    page?: IDataSet[];
    parser?: any;
}

type ResolveResult<T extends IAgentList> = {
    [key in keyof T]: T[key] extends IAgentBase<infer R> ? R : never;
}

// в реальности все иначе, написал для понимания желаемого результата
async function runAgents<T extends IAgentList>(agents: T): Promise<ResolveResult<T>> {
    const result: ResolveResult<T> = {} as any;
    Object.keys(agents).forEach(
      async key => result[key as keyof T] = await agents[key as keyof T].parse()
    );
    return result;
}

async function main() {
    const agents : IAgents = {} as any;
    const result = await runAgents(agents)
    result // typed
}
Ответ написан
Пригласить эксперта
Ответы на вопрос 1
Ответ написан
Комментировать
Ваш ответ на вопрос

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

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