Read Done Value
reader.read returns a real `{ value: undefined, done: true }` record once the stream is closed — not the chunk type's zero value — and a controller's desiredSize is `null` once the stream has errored (vs `0` once merely closed). These are the last `T | undefined` adopters, reusing the shared presence-flagged optional.
const rs = new ReadableStream<number>({
start: (c) => {
c.enqueue(1);
c.enqueue(2);
c.close();
},
});
const reader = rs.getReader();
// Drain via destructuring. On the closed read, `value` is a real `undefined`.
while (true) {
const { value, done } = await reader.read();
if (done) {
console.log("done — value is undefined:", value === undefined);
break;
}
// `value` is `number | undefined` here; `done === false` guarantees it is
// present, so assert with `!` (or narrow with `if (value !== undefined)`).
console.log("chunk:", value! * 10);
}
// desiredSize is `0` once closed, but `null` once errored.
new ReadableStream<number>({
start: (c) => {
c.close();
console.log("desiredSize once closed:", c.desiredSize);
},
});
new ReadableStream<number>({
start: (c) => {
c.error(new Error("stop"));
console.log("desiredSize once errored:", c.desiredSize);
},
});View source on GitHubexamples/streams/read_done_value.ts