在TypeScript中如何将Promise<AsyncIterableIterator<T>>转为AsyncIterableIterator<T>?
Promise<AsyncIterableIterator<T>> into AsyncIterableIterator<T> in TypeScript Absolutely! You can absolutely implement the function you're asking for in TypeScript. Since we're dealing with a promise (which is inherently asynchronous), we can't extract the iterator synchronously—but we can create a wrapper AsyncIterableIterator that handles the async resolution behind the scenes. Let's break this down step by step.
Here's a complete, production-ready implementation:
function unwrapPromiseAsyncIterator<T>( promiseIterator: Promise<AsyncIterableIterator<T>> ): AsyncIterableIterator<T> { // Cache the resolved iterator to avoid re-awaiting the promise on every call let resolvedIterator: AsyncIterableIterator<T> | undefined; // Helper to fetch (and cache) the resolved iterator const getIterator = async () => { if (!resolvedIterator) { resolvedIterator = await promiseIterator; } return resolvedIterator; }; return { // Make the wrapper itself async iterable (required for `for await...of` loops) [Symbol.asyncIterator]() { return this; }, // Delegate the `next()` call to the resolved iterator async next(...args: Parameters<AsyncIterableIterator<T>['next']>) { const iterator = await getIterator(); return iterator.next(...args); }, // Optional: Delegate `return()` to handle early loop termination (e.g., `break`) async return(value?: T) { const iterator = await getIterator(); if (typeof iterator.return === 'function') { return iterator.return(value); } return { done: true, value }; }, // Optional: Delegate `throw()` to propagate errors properly async throw(error?: any) { const iterator = await getIterator(); if (typeof iterator.throw === 'function') { return iterator.throw(error); } throw error; } }; }
How This Works:
- Caching: We store the resolved iterator once the promise resolves, so we only wait for the promise once—even if
next()is called multiple times. This keeps things efficient. - Full Interface Compliance: The wrapper implements every part of the
AsyncIterableIteratorinterface, including[Symbol.asyncIterator],next(),return(), andthrow(). This ensures it works seamlessly with all async iterator consumers likefor await...ofloops. - Delegation: All iterator operations are passed through to the underlying resolved iterator once the promise is ready. The optional
return()andthrow()methods ensure proper cleanup (like closing a stream if you break out of a loop early) and error propagation.
Usage Example
Let's test this with a sample async iterator wrapped in a promise:
// A function that returns a promise of an async iterator async function getDelayedAsyncIterator(): Promise<AsyncIterableIterator<number>> { // Simulate an async operation (e.g., fetching data from an API) await new Promise(resolve => setTimeout(resolve, 200)); // Return an async iterator that yields 1, 2, 3 return { [Symbol.asyncIterator]() { return this; }, current: 0, async next() { this.current++; if (this.current <= 3) { return { done: false, value: this.current }; } return { done: true, value: undefined }; } }; } // Unwrap the promise-wrapped iterator const usableIterator = unwrapPromiseAsyncIterator(getDelayedAsyncIterator()); // Use it in a for await...of loop async function iterate() { for await (const num of usableIterator) { console.log(num); // Logs 1, 2, 3 in sequence } } iterate();
Key Note:
You can't convert a Promise<AsyncIterableIterator<T>> to AsyncIterableIterator<T> synchronously—promises are asynchronous by design, so we have to defer iterator operations until the promise resolves. The wrapper handles this complexity transparently, making the iterator behave like a normal async iterable.
内容的提问来源于stack exchange,提问作者Trident D'Gao

