Last active
November 21, 2023 00:30
-
-
Save leontastic/68a856f1b6c40c7a3d19c971bcae1127 to your computer and use it in GitHub Desktop.
TS promise utils
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
export type PromiseFromProps<PromiseMap> = Promise< | |
{ | |
[Property in keyof PromiseMap]: Awaited<PromiseMap[Property]>; | |
} | |
>; | |
export const fromProps = async <T>(object: T): PromiseFromProps<T> => { | |
// invert the object so that we get an array of promises resolving to key-value entries | |
const promises = Object.entries(object).map(([property, promise]) => | |
Promise.resolve(promise).then((result) => [property, result]), | |
); | |
// get the promises out of the object | |
const results = await Promise.all(promises); | |
return Object.fromEntries(results); | |
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import { fromProps } from './promise'; | |
describe('fromProps', () => { | |
it('should return a promise resolving to the input object with promise properties already resolved', async () => { | |
const result = await fromProps({ | |
a: Promise.resolve('bar'), | |
b: Promise.resolve('baz'), | |
c: Promise.resolve('foo'), | |
}); | |
expect(result.a).toBe('bar'); | |
expect(result.b).toBe('baz'); | |
expect(result.c).toBe('foo'); | |
}); | |
it('should gracefully support non-promise properties', async () => { | |
const result = await fromProps({ | |
a: 'bar', | |
b: 'baz', | |
c: 'foo', | |
}); | |
expect(result.a).toBe('bar'); | |
expect(result.b).toBe('baz'); | |
expect(result.c).toBe('foo'); | |
}); | |
it('should reject with the first error encountered', async () => { | |
let rejectPromise: (rejectValue: any) => void; | |
const errorPromise = new Promise((_, reject) => { | |
rejectPromise = reject; | |
}); | |
fromProps({ | |
a: Promise.resolve('bar'), | |
b: Promise.resolve('baz'), | |
c: errorPromise, | |
}) | |
.then(() => { | |
throw new Error('should not resolve if inner promises reject'); | |
}) | |
.catch((error) => { | |
expect(error.message).toBe('rejected!'); | |
}); | |
setTimeout(() => rejectPromise(new Error('rejected!')), 0); | |
}); | |
}); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment