import type { FutureBoolean } from './boolean' ; export type MaybeFuture < T > = T | Future < T > ; type UnpackFuture < T > = T extends Future < infer U > ? U : T ; export class Future < T > { constructor ( public resolve ) { } static resolve < T > ( value ) { return value instanceof Future ? value . resolve ( ) : value ; } static create < T > ( message = 'Trying to get value from unresolved future.' ) { let resolved = false ; let value ; const future = new Future < T > ( ( ) => { if ( ! resolved ) { throw new Error ( message ) ; } return value ; } ) ; return [ future , ( result ) => { resolved = true ; value = result ; } , ] as const ; } map < U > ( fn ) { return new Future ( ( ) => Future . resolve ( fn ( this . resolve ( ) ) ) ) ; } get < U extends keyof T > ( key ) { return this . map ( ( value ) => value [ key ] ) as any ; } equals ( other ) { throw new Error ( 'This will get overridden.' ) ; } } type FutureTuple < T > = T extends [ infer V , ... infer Rest ] ? [ Future < V > , ... FutureTuple < Rest > ] : [ ] ; type FutureArray < T > = T extends Array < any > ? FutureTuple < T > : Future < T > [ ] ; type UnpackArray < T > = T extends FutureArray < infer U > ? U : never ; type ForceArray < T > = T extends Array < any > ? T : T [ ] ; export function reduce < T extends FutureArray < any > , R > ( futures , fn ) { return new Future ( ( ) => Future . resolve ( fn ( ... ( ( futures as any [ ] ) . map ( ( f ) => f . resolve ( ) ) as ForceArray < UnpackArray < T > > ) ) ) ) ; }