Where communities thrive


  • Join over 1.5M+ people
  • Join over 100K+ communities
  • Free without limits
  • Create your own community
People
Activity
    Conrad Buck
    @conartist6
    @edwardb96 7.0.1 is up with the fix and is tested working as shipped.
    Edward Brown
    @edwardb96
    Thanks, that's working for me now
    Caleb Cox
    @canac
    Is there an API or best-practices for converting a Promise into an iterable? I'm trying to zip a repeated promise and an iterable, and I can't figure out how to do that. In rxjs, there's a from method that convers Promises into iterables, so I'm wondering if iter-tools has something similar because I couldn't find anything. Thanks!
    Conrad Buck
    @conartist6
    Hi @canac. The simplest way I think would be asyncWrap([promise]).
    Caleb Cox
    @canac
    Oh OK, thanks! Realized I could also make my own function to do that.
    async function* promiseToAsyncGenerator<T>(promise: Promise<T>): AsyncGenerator<T> {
      yield await promise;
    }
    Caleb Cox
    @canac
    Unless, I'm doing something wrong, asyncWrap([promise]) doesn't work. It doesn't accept an array of promises, at least in the TypeScript typings.
    Conrad Buck
    @conartist6
    Oh that may be a bug. An array of promises is definitely acceptable, but the typings may not know about it
    Conrad Buck
    @conartist6
    Opened a PR to fix the types: iter-tools/iter-tools#427
    Conrad Buck
    @conartist6
    That fix is released in 7.1.0.
    Conrad Buck
    @conartist6
    By the way, the type that was amended is used by most methods that accept async iterable inputs, so if you're just feeding the array of promises into some other iter-tools method there's no need to use asyncWrap.
    Caleb Cox
    @canac
    Fantastic! I'll check that out
    Caleb Cox
    @canac
    It works! Now I'm running into a typing issue with asyncZip. It expects each observable to be of the same type, but mine are not. I'm not sure how that would be expressed in the general case, but for just two sources, it should be:
    declare function asyncZip<T, U>(source1: AsyncWrappable<T>, source2: AsyncWrappable<U>): AsyncIterableIterator<[T, U]>;
    Conrad Buck
    @conartist6
    Yeah prior to the current version TS didn't have a good way to generalize so there are a whole slew of lines like the one you wrote above with another overload for each number of arguments.
    The goal for the next version is to use the generalized stuff. For now we could probably add those overloads though.
    I'd probably support two and three argument calls, which sounds like it would work for you. Should be an easy change. Would you be interested in writing it or should i?
    Caleb Cox
    @canac
    Yeah, I can put a PR together for the 2 and 3 args case.
    Conrad Buck
    @conartist6
    The file you'd be wanting to change is $zip.d.ts
    Conrad Buck
    @conartist6
    I write sync and async code together, so once you make your changes you run yarn generate to build zip.d.ts and async-zip.d.ts from $zip.d.ts.
    Caleb Cox
    @canac
    Thanks for the direction! Almost done with the PR. Does this project use typings tests? If so I'll add some, but all I'm seeing is functionality tests.
    Caleb Cox
    @canac
    OK, nevermind since the tests are in TypeScript, we'll get errors if the types don't match up, so I'll do it that way.
    Caleb Cox
    @canac
    Conrad Buck
    @conartist6
    Yep, the runtime tests are evaluated by typescript, and there are also some type tests for things that runtime tests don't make sense to capture -- those are the .spec.ts files, but these days I'm not adding them if there's no particular need. If I had type coverage it would be more obvious, but I haven't looked to see if such a thing exists
    Caleb Cox
    @canac
    Makes sense. If you were ever to try to add that, tsd on npm has some helpers. As an example, Vue uses it: https://github.com/vuejs/vue-next/blob/4ca4666d58ee8025570dc14f1c163bdeac9c6012/test-dts/ref.test-d.ts
    Conrad Buck
    @conartist6
    Thanks for the tip, I'll check it out!
    Caleb Cox
    @canac
    Also, what is the expected return value of wrapAsync([Promise.resolve(1)])? I'd expect the iterable to have a single value 1, but the iterable has a single value of a Promise that resolves to 1. Not sure if this is a bug or intended behavior.
    Conrad Buck
    @conartist6
    Hmm yeah that's true. But a for await..of loop has no problem iterating through that structure, which means all our methods work and those of other libraries should as well.
    Conrad Buck
    @conartist6
    I found a thread about this recently as well in relation to the tc39 iterator helpers proposal: ReactiveX/IxJS#309
    Caleb Cox
    @canac
    OK, so it's a situation again of the functionality works, but the typings don't match?
    To me it seems like unwrapping promises is more intuitive behavior.
    Conrad Buck
    @conartist6
    So I think the problem here is that I'm using yield* and yield* doesn't have quite the same mechanics as for await (const v of it) yield v
    But it's pretty desirable to use yield*. It saves stack frames and gives queues to the engine that may permit additional kinds of optimizations now or in the future
    Conrad Buck
    @conartist6
    I think the correct compromise would be to use a for await..of instead of yield* in the implementation of asyncWrap. I already have the concept of trusted and untrusted iterators. Inside the library I pass iterators around between various methods and classes. Those are trusted, meaning no validation is done and correct semantics are assumed. Those methods over trusted inputs are exported with the __ prefix. A wrapper layer converts the __ methods to the unprefixed ones which validate inputs, including using wrap to turn untrusted iterators into trusted ones.
    Caleb Cox
    @canac
    I took a stab at unwrapping promise types in AsyncIterableIterator iter-tools/iter-tools#429
    That makes sense what you're saying and seems like a good compromise
    Conrad Buck
    @conartist6
    Hmm I think I was wrong though -- it looks to me like yield* does "unwrap": (async function*() { yield* [Promise.resolve(1)] })()[Symbol.asyncIterator]().next().then(s => console.log(s.value))
    1
    In which case your PR updating the typedefs to match would be all that's needed.
    Caleb Cox
    @canac
    Oh interesting! I didn't know that about yield*
    Conrad Buck
    @conartist6
    Neither did I
    Merged that PR
    Caleb Cox
    @canac
    Wait, in your snippet, the yield* isn't doing the wrapping, the then call is. It looks like yield* still doesn't unwrap.
    console.log((async function*() { yield* [Promise.resolve(1)] })()[Symbol.asyncIterator]().next())
    Promise {<pending>}
    Conrad Buck
    @conartist6
    Async iterators are always going to return a promise from next(). You are correct that then() could unwrap a promise returning a promise, but that isn't what happens. You would see a Promise<{done: false, value: Promise<1>}> if yield* was not unwrapping, but instead you just get Promise<{done: false, value: 1}> which is what you want.
    Caleb Cox
    @canac
    OK, didn't realize that asyncIterators always return a promise, but that makes sense.
    Conrad Buck
    @conartist6
    Indeed they do because you don't necessarily know if you're done synchronously
    Conrad Buck
    @conartist6
    v7.1.1 is out. See CHANGELOG.md for details.
    Conrad Buck
    @conartist6
    v7.1.2 is out and deprecates v7.1.1 (which contained potentially breaking change in core types)