sizeDelimitedDecodeStream declares its input as AsyncIterable<Uint8Array>:
https://github.com/bufbuild/protobuf-es/blob/main/packages/protobuf/src/wire/size-delimited.ts#L105
but consumes it with for await...of:
https://github.com/bufbuild/protobuf-es/blob/main/packages/protobuf/src/wire/size-delimited.ts#L111
for await...of accepts sync iterables as well as async ones — it awaits each yielded value — so the implementation already works with an Iterable. Only the declared type rules it out.
This shows up when decoding a buffer that is already in memory, which seems like a common case for the size-delimited format: reading a file, or a value out of local storage. There is nothing to stream, but the signature still requires an AsyncIterable, so callers wrap the single buffer in an async generator that never awaits anything:
import { sizeDelimitedDecodeStream } from "@bufbuild/protobuf/wire";
// what a caller would like to write
for await (const message of sizeDelimitedDecodeStream(schema, [bytes])) {
// Argument of type 'Uint8Array[]' is not assignable to parameter of type
// 'AsyncIterable<Uint8Array>'.
// Property '[Symbol.asyncIterator]' is missing in type 'Uint8Array[]' but
// required in type 'AsyncIterable<Uint8Array>'. ts(2345)
}
// what they write instead
async function* single(bytes: Uint8Array): AsyncGenerator<Uint8Array> {
yield bytes;
}
for await (const message of sizeDelimitedDecodeStream(schema, single(bytes))) {
// ...
}
The wrapper is inert at runtime, and linters that check for unnecessary async flag it, since the generator never awaits.
I confirmed that passing the array directly decodes correctly when the type error is suppressed, which is what led me to look at the implementation.
Observed on 2.12.0; the source links above are main as of 2.13.0.
sizeDelimitedDecodeStreamdeclares its input asAsyncIterable<Uint8Array>:https://github.com/bufbuild/protobuf-es/blob/main/packages/protobuf/src/wire/size-delimited.ts#L105
but consumes it with
for await...of:https://github.com/bufbuild/protobuf-es/blob/main/packages/protobuf/src/wire/size-delimited.ts#L111
for await...ofaccepts sync iterables as well as async ones — it awaits each yielded value — so the implementation already works with anIterable. Only the declared type rules it out.This shows up when decoding a buffer that is already in memory, which seems like a common case for the size-delimited format: reading a file, or a value out of local storage. There is nothing to stream, but the signature still requires an
AsyncIterable, so callers wrap the single buffer in an async generator that never awaits anything:The wrapper is inert at runtime, and linters that check for unnecessary
asyncflag it, since the generator never awaits.I confirmed that passing the array directly decodes correctly when the type error is suppressed, which is what led me to look at the implementation.
Observed on 2.12.0; the source links above are
mainas of 2.13.0.