Как набирать функцию combPromise в машинописи - PullRequest
0 голосов
/ 05 декабря 2018

У меня есть эта существующая функция JS, которая является альтернативой интерфейсу Promise.all().Есть ли способ ввести его с помощью TS?

// Like Promise.all() but taking an object<key,promise<?>> and returning object<key,promiseValue>
export const combinePromises = obj => {
   const keys = Object.keys(obj);
   const values = Object.values(obj);
   return Promise.all(values).then(results => {
      const combinedResult = {};
      results.forEach((result, i) => {
         const key = keys[i];
         combinedResult[key] = result;
      });
      return combinedResult;
   });
};

Я хотел бы иметь возможность сделать

const {user,company} = await combinePromises({
    user: fetchUser(), 
    company: fetchCompany()
});

Учитывая, что функции выборки набраны, я ожидаю ответ (пользовательи компания), чтобы быть набранным также.

Ответы [ 2 ]

0 голосов
/ 05 декабря 2018

Я только что сделал:

const [ user, company ] = await Promise.all([
  fetchUser(),
  fetchCompany()
]);

и получил правильные типы.

https://stackblitz.com/edit/typescript-combine-promise-typed

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

Это не хорошоответ, потому что он не отвечает непосредственно на вопрос ОП.Но это может быть полезно для других, зная, что вы можете использовать Promise.all таким образом.и, возможно, ОП мог бы рассмотреть возможность использования Promise.all напрямую.

0 голосов
/ 05 декабря 2018

Во-первых, обратите внимание, что combinePromises должен вернуть Обещание, поскольку Promise.all возвращает Обещание.

function combinePromises(obj): Promise<...>

Теперь, что нужно добавить в ...?Ну, вы хотите, чтобы результат был в основном тем же объектом, который был передан, но с разрешенными значениями.

Применение тех же ключей

Чтобы возвращаемое значение имело те же ключи, что ипереданное в значение, вам нужно использовать обобщенные значения и оператор keyof:

type MyType<T> = { [K in keyof T]: ... };
function combinePromises<T>(obj: T): Promise<MyType<T>>

Теперь, после того как вы await получите результат combinePromises, вы получитеобъект, ключи которого совпадают с ключами переданного объекта.

Применение аналогичных значений

Вторая часть немного сложнее, поскольку вы не можете развернуть Promises для извлечения внутренних типов.Тем не менее, вы можете определить условный тип , который выводит тип того, что передано Promise<...>:

type ThenArg<T> = T extends Promise<infer U> ? U : any;

Определение означает, что если тип T предоставлен ThenArg<...> можно присвоить Promise<infer U>, затем тип возврата U.В противном случае по умолчанию введите any.

, поэтому ThenArg<Promise<User>> вернет User.

Ваше окончательное определение типа и сигнатура функции должны выглядеть следующим образом:

type MyType<T> = { [K in keyof T]: ThenArg<T[K]> }; // T[K] is the Promise value of the object passed in
type ThenArg<T> = T extends Promise<infer U> ? U : any;

function combinePromises<T>(obj: T): Promise<MyType<T>>

И объявление combinedResult должно выглядеть следующим образом:

const combinedResult: MyType<T> = {} as MyType<T>;

Объект того же типа, только без слоя Promise, поскольку внутри Promise.all then они уже разрешены.


Полное решение будет выглядеть примерно так:

async function fetchUser(): Promise<User> {
    return new User();
}
async function fetchCompany(): Promise<Company> {
    return new Company();
}

class User { name:string }
class Company { }

type MyType<T> = { [K in keyof T]: ThenArg<T[K]> };
type ThenArg<T> = T extends Promise<infer U> ? U : any;

export const combinePromises = function combinePromises<T>(obj: T): Promise<MyType<T>> {
    const keys = Object.keys(obj);
    const values = Object.values(obj);
    return Promise.all(values).then((results) => {
        const combinedResult: MyType<T> = {} as MyType<T>;
        results.forEach((result, i) => {
            const key = keys[i];
            combinedResult[key] = result;
        });
        return combinedResult;
    });
};

(async () => {
    const { user, company } = await combinePromises({
        user: fetchUser(),
        company: fetchCompany()
    });
    user.name; // we can access user.name since that's a member of User
})();
...