Skip to content

Instantly share code, notes, and snippets.

@emiloberg
Created September 11, 2023 10:43
Show Gist options
  • Save emiloberg/c2e598be1cd33d8a300517ff1bd427cb to your computer and use it in GitHub Desktop.
Save emiloberg/c2e598be1cd33d8a300517ff1bd427cb to your computer and use it in GitHub Desktop.
Type-safe promise.allSettled where a promise may or may not be required
type PromiseObject<T> = {
promise: Promise<T>;
required: boolean;
};
type PromiseResult<T> = T extends Promise<infer U> ? U : never;
type PromiseResults<T extends readonly PromiseObject<unknown>[]> = {
[K in keyof T]: T[K]['required'] extends true
? PromiseResult<T[K]['promise']>
: PromiseResult<T[K]['promise']> | null;
};
/**
* Takes a list of promises where they can either be required or not.
* If a required promise fails, the entire function will throw.
* If a non-required promise fails, it will return null value for that promise.
*
* @example
* const [
* alpha,
* beta,
* gamma
* ] = await prioritizedPromiseAll([
* { promise: Promise.resolve(1), required: true },
* { promise: Promise.resolve("string"), required: false },
* { promise: Promise.resolve(true), required: true },
* ]);
*
* alpha
* // ^? number
* beta
* // ^? string | number
* gamma
* // ^? boolean
*
*/
async function tieredPromiseAll<const T extends readonly PromiseObject<unknown>[]>(promises: T) {
const settledPromises = await Promise.allSettled(promises.map((p) => p.promise));
return promises.map((promiseObject, index) => {
const settledPromise = settledPromises[index];
if (settledPromise.status === 'fulfilled') {
return settledPromise.value as PromiseResult<(typeof promiseObject)['promise']>;
} else {
if (promiseObject.required) {
throw settledPromise.reason;
} else {
return null;
}
}
}) as PromiseResults<T>;
}
const example = async () => {
const [alpha, beta, gamma] = await tieredPromiseAll([
{ promise: Promise.resolve(1), required: true },
{ promise: Promise.resolve('string'), required: false },
{ promise: Promise.resolve(true), required: true },
]);
alpha;
// ^?
beta;
// ^?
gamma;
// ^?
};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment