Как задать типы входных параметров для функции, если возвращаемый тип указан как Function[]?

Как можно модифицировать функцию `fetchPromiseAll`, чтобы она возвращала ожидаемые интерфейсы для данных, получаемых от переданных в параметр `functions` функций? В исходном примере результатом выполнения становится тип `any` для `data` и `opfs`, и хотелось бы получить понятные интерфейсы вместо этого.
  • 28 августа 2024 г. 4:14
Ответы на вопрос 2
Для того чтобы типизировать входные параметры функции `fetchPromiseAll`, которая принимает массив функций, возвращающих промисы, и возвращает массив результатов, можно воспользоваться обобщениями (generics) в TypeScript. Это позволит вам задать типы входных функций и соответствующие ожидаемые типы данных, которые они возвращают.

Предположим, что каждая функция из массива `functions` возвращает `Promise<T>`, где `T` - это тип данных, который возвращается. Мы можем использовать обобщение для определения типа `T` и затем использовать его для определения возвращаемого типа функции `fetchPromiseAll`.

Вот пример того, как можно реализовать такую функцию:

```typescript
async function fetchPromiseAll<T>(functions: (() => Promise<T>)[]): Promise<T[]> {
    return Promise.all(functions.map(fn => fn()));
}

// Пример использования:

interface Data {
    id: number;
    value: string;
}

const fetchData1 = async (): Promise<Data> => {
    // Имитация асинхронного запроса
    return new Promise<Data>(resolve => {
        setTimeout(() => {
            resolve({ id: 1, value: 'Data 1' });
        }, 1000);
    });
};

const fetchData2 = async (): Promise<Data> => {
    return new Promise<Data>(resolve => {
        setTimeout(() => {
            resolve({ id: 2, value: 'Data 2' });
        }, 1000);
    });
};

const result = fetchPromiseAll<Data>([fetchData1, fetchData2]);

result.then(data => {
    console.log(data); // Должен вывести массив Data
});
```

### Объяснение:

1. **Обобщения**: Мы объявляем функцию `fetchPromiseAll` с обобщением `<T>`, что позволяет использовать тип `T` внутри самой функции, например как тип для промисов.

2. **Тип массива функций**: Мы задаем входной параметр `functions` как массив функций, где каждая функция возвращает `Promise<T>`.

3. **Возврат типа**: Возвращаемый тип функции — это `Promise<T[]>`, что означает, что когда все промисы будут выполнены, мы получим массив результатов типа `T`.

4. **Пример использования**: Мы создаем два асинхронных метода, которые возвращают данные типа `Data`. При вызове `fetchPromiseAll` TypeScript понимает, что возвращаемые данные будут соответствовать интерфейсу `Data`, и это дает нам возможность безопасно работать с результатами, полученными из промисов.

Таким образом, используя обобщения, вы можете четко указать, каких типов данные вы ожидаете, получая более строгую типизацию в вашем коде.
Как-то так: 
function fetchAll<T extends readonly Function[]>(functions: T, data?: Arguments<T>): Promise<Returns<T>> {
	return Promise.all(
		functions.map((func, index) => func(data ? data[index] : undefined))
	) as Promise<Returns<T>>;
}


type Returns<T extends readonly unknown[]> = {
  [K in keyof T]: T[K] extends (...args: any[]) => Promise<infer R> ? R : never;
};

type Arguments<T extends readonly unknown[]> = {
  [K in keyof T]: T[K] extends (arg: infer R) => unknown ? R : never;
};
Похожие вопросы