-
Notifications
You must be signed in to change notification settings - Fork 3k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feat(ReadableStreams): Support for ReadableStreams e.g. from(readableStream)
#6163
Conversation
| PromiseLike<T> | ||
| ArrayLike<T> | ||
| Iterable<T> | ||
| ReadableStreamLike<T>; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm happy to change this and the other places to have a consistent order, if there's a preference.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I guess the order of this should match the runtime order.
e166f9f
to
9dc47ae
Compare
9dc47ae
to
0ba9e64
Compare
import { isFunction } from './isFunction'; | ||
|
||
export interface ReadableStreamLike<T> { | ||
getReader(): ReadableStreamDefaultReader<T>; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'll give this a proper review later, but I don't think we can rely on - or explicitly reference using a ///
comment - this type: ReadableStreamDefaultReader<T>
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah great catch. I'll stub it out too since it's easy.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done. a7e9b56
getReader(): ReadableStreamDefaultReaderLike<T>; | ||
} | ||
|
||
export async function* readableStreamLikeToAsyncGenerator<T>(readableStream: ReadableStreamLike<T>): AsyncGenerator<T> { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just thinking... that while this is definitely the coolest way. The lame way might be more efficient, something like:
export function readableStreamLikeToAsyncGenerator(readableStream: ReadableStreamLike<T>): AsyncGenerator<T> {
const reader = readableStream.getReader();
return {
[Symbol.asyncIterator]() { return this; },
async next() {
return reader.read();
},
async throw(err) {
reader.releaseLock();
throw err;
},
async return() {
reader.releaseLock();
return { done: true };
}
}
}
But maybe I'm totally wrong. Just something I was thinking about. I guess if there was an error during the execution of next
above, the lock wouldn't get released unless you had a try/catch in there, so maybe this isn't the best idea.
General approval from me. Pending @cartant's approval. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM
I had a look at adding a dtslint test for a IMO, we should export In the dtslint test I had to import it like this: import { from, of, animationFrameScheduler } from 'rxjs';
import { ReadableStream } from 'web-streams-polyfill';
import { ReadableStreamLike } from '../../src/internal/util/isReadableStreamLike'; In the test, it('should accept a ReadableStream', () => {
const stream = new ReadableStream<string>({
pull(controller) {
controller.enqueue('x');
controller.close();
},
});
// Nope, this expectation fails 'cause Observable<any> is inferred
const o = from(stream); // $ExpectType Observable<string>
}); However, trying to assign it to an explicitly-typed it('should accept a ReadableStream', () => {
const stream: ReadableStreamLike<string> = new ReadableStream<string>({
pull(controller) {
controller.enqueue('x');
controller.close();
},
});
const o = from(stream); // $ExpectType Observable<string>
}); compilation fails with this TypeScript error:
TypeScript is such a party pooper. |
@cartant @jayphelps I've added a couple of commits (it should have been one, but I rushed the first one and forgot some important bits):
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Noice.
Description:
Support ReadableStream and other similar objects by checking for
getReader()
existence. In theory this isn't foolproof, but in practice I can't see this ever actually causing issues in practice.instanceof
checks don't work with cross-Realm instances and neither ReadableStream nor ReadableStreamDefaultReader implement Symbol.asyncIterator yet (which is why this custom support is needed)Related issue (if exists):
Closes #6006