Как превратить тип функции в ее асинхронный эквивалент в TypeScript? - PullRequest
0 голосов
/ 01 декабря 2019

Как я могу набрать эту функцию относительно ее ввода fn?

function makeAsync(fn) {
  return async (...args) => fn(...args);
}

Она возвращает функцию, идентичную ее вводу, но вместо возврата Type она вернет Promise<Type>

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

const a = () => 1; // Type () => number;
const b = makeAsync(a); // Type () => Promise<number>;
const c = makeAsync(b); // Type () => Promise<number>; // ✅, not Promise<Promise<number>>

Это работает, но немного многословно

// Unwraps a Promise<T> value into just T, so we never get Promise<Promise<T>>
type Unpromise<MaybePromise> = MaybePromise extends Promise<infer Type> ? Type : MaybePromise;

// Like ReturnType, except it returns the unwrapped promise also for async functions
type AsyncReturnType<T extends (...args: any[]) => any> = Unpromise<ReturnType<T>>

// For a `() => T` function it returns its async equivalent `() => Promise<T>`
type PromisedFunction<T extends (...args: any[]) => any> =
    (...args: Parameters<T>) => Promise<AsyncReturnType<T>>;
function makeAsync<T extends (...args: any[]) => any>(fn: T): PromisedFunction<T> {
  return async (...args) => fn(...args);
}

TypeScript Playground link

Есть ли лучшие / более короткие способы достижения этого?

1 Ответ

1 голос
/ 01 декабря 2019

Вы можете немного сократить типы, задав отдельные параметры типа A, R для параметров функции и типа возвращаемого значения, чтобы они выводились автоматически. Тогда легко обернуть Promise вокруг R в makeAsync2 ( семпл ):

declare function makeAsync2<A extends any[], R>(fn: (...args: A) => R): (...args: A) => Promise<R>

const c = (arg1: number, arg2: string[]) => 1; // (arg1: number, arg2: string) => number
const d = makeAsync2(c); // (arg1: number, arg2: string[]) => Promise<number>
const cResult = c(3, ["s"]) // number
const dResult = d(3, ["s"]) // Promise<number>

Редактировать:

Если функция вводаfn потенциально может сам вернуть обещание, мы можем установить его тип возвращаемого значения для объединения R | Promise<R> ( sample ):

function makeAsync2<A extends any[], R>(fn: (...args: A) => R | Promise<R>): (...args: A) => Promise<R> {
  return async (...args) => fn(...args);
}

const e = (arg1: string) => Promise.resolve(3) // (arg1: string) => Promise<number>
const f = makeAsync2(e); // (arg1: string) => Promise<number>
const eResult = e("foo") // Promise<number>
const fResult = f("foo") // Promise<number>
...