Skip to content

Instantly share code, notes, and snippets.

@jtbandes
Created February 16, 2022 17:45
Show Gist options
  • Save jtbandes/5360453f2895cbf552ec71b240b53009 to your computer and use it in GitHub Desktop.
Save jtbandes/5360453f2895cbf552ec71b240b53009 to your computer and use it in GitHub Desktop.
type MaybeAwait<P> = P extends Promise<infer T> ? T : P;
function maybeAsync<Args extends unknown[], TYield, TReturn>(
body: (...args: Args) => Generator<TYield, TReturn, MaybeAwait<TYield>>
): (...args: Args) => (TYield extends Promise<infer _P> ? Promise<TReturn> : TReturn);
function maybeAsync<Args extends unknown[], TYield, TReturn>(
body: (...args: Args) => Generator<TYield, TReturn, MaybeAwait<TYield>>
): (...args: Args) => (Promise<TReturn> | TReturn) {
return (...args: Args) => {
let gen = body(...args);
function run(...args: [] | [TYield extends Promise<infer P> ? P : TYield]): Promise<TReturn> | TReturn {
let result = gen.next(...args);
while (!result.done) {
if (result.value instanceof Promise) {
return result.value.then(run);
} else {
result = gen.next(result.value as MaybeAwait<TYield>); // https://github.com/microsoft/TypeScript/issues/47901
}
}
return result.value;
}
return run();
}
}
interface Filelike {
read(offset: number, length: number): Promise<Uint8Array> | Uint8Array;
}
class Adder<F extends Filelike> {
constructor(private file: F) {}
*_sum(): Generator<ReturnType<F['read']>, number, MaybeAwait<ReturnType<F['read']>>> {
let sum = 0;
const bytes = yield (this.file.read(0, 3) as ReturnType<F['read']>); // https://github.com/microsoft/TypeScript/issues/47900
sum = bytes.reduce((acc, val) => acc + val, sum);
const bytes2 = yield (this.file.read(10, 3) as ReturnType<F['read']>); // https://github.com/microsoft/TypeScript/issues/47900
sum = bytes2.reduce((acc, val) => acc + val, sum);
return sum;
}
sum = maybeAsync(this._sum.bind(this));
}
function makeArray(start: number, len: number) {
let result = new Uint8Array(len);
for (let i = 0; i < len; i++) {
result[i] = start + i;
}
return result;
}
let sumSync: number = new Adder({ read: (start, len) => makeArray(start, len) }).sum();
console.log("sum1", sumSync);
let sumAsync: Promise<number> = new Adder({ read: async (start, len) => makeArray(start, len) }).sum();
sumAsync.then((val) => console.log("sum2", val));
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment