#typescript #typescript-typings #typescript-generics #typescript2.0
Вопрос:
У меня есть mapResponse
функция, которая принимает другую функцию (вызывающую) и функцию сопоставления. Результатом функции должна быть 3-я функция, представляющая собой комбинацию предоставленных обратных вызовов: она должна принимать параметры вызывающего абонента, но возвращает результат сопоставления.
Вызывающий может привести к Обещанию, поэтому Обещание должно быть распаковано до того, как картограф получит свои параметры.
Поэтому мой вопрос не в реализации (что уже сделано), а в типизациях. Как я могу описать такое поведение с помощью объявлений машинописного текста?
export function mapResponse<
Caller extends (...args: any[]) => unknown,
Mapper extends <R>(response: Unpacked<ReturnType<Caller>>) => R
>(
caller: Caller,
mapper: Mapper
): (...args: Parameters<Caller>) => ReturnType<Mapper> {
return (...args: Parameters<Caller>) => {
const res = caller(...args) as Unpacked<ReturnType<Caller>>
if (res instanceof Promise) {
return res.then(mapper) as ReturnType<Mapper>
}
return mapper(res)
}
}
Вот Unpacked
декларация, если она кому-то нужна:
export type Unpacked<T> = T extends (infer U)[]
? U : T extends (...args: any[]) => infer U
? U : T extends Promise<infer U>
? U : T
Ответ №1:
Я бы объявил функцию следующим образом:
type Unpacked<T> = T extends Promise<infer U> ? U : T;
declare function mapResponse
<
TCaller extends (...args: any[]) => any,
TMapper extends (input: Unpacked<ReturnType<TCaller>>) => any
>(caller: TCaller, mapper: TMapper):
TMapper extends (input: Unpacked<ReturnType<TCaller>>) => infer R ? (...args: Parameters<TCaller>) => R : never;
const func1 = mapResponse((a: number, b: number) => a b, sum => sum.toString()); // (a: number, b: number) => string
const func2 = mapResponse((a: number, b: number) => Promise.resolve(a b), sum => sum.toString()); // (a: number, b: number) => string
Разница по сравнению с вашим примером заключается в том, что TMapper
также должно быть extends
определение с правой стороны, чтобы infer R
правильно.
Пример игровой площадки для машинописи здесь: https://tsplay.dev/wOav6m