Skip to Content

typia.protobuf.*Decode โ€” Protocol Buffer bytes โ†’ TypeScript object

signatures
namespace protobuf { function decode<T>(buffer: Uint8Array): Resolved<T>; function isDecode<T>(buffer: Uint8Array): Resolved<T> | null; function assertDecode<T>(buffer: Uint8Array): Resolved<T>; function validateDecode<T>(buffer: Uint8Array): IValidation<Resolved<T>>; }

The decoder reads T at compile time and emits a hand-rolled binary reader for that shape โ€” same model as the encoder, in reverse.

First example

hello-decode.ts
import typia from "typia"; interface User { id: string; age: number; hobbies: string[]; } const bytes: Uint8Array = await fetchBytesSomehow(); const user = typia.protobuf.assertDecode<User>(bytes); // โ†’ User, with type tag constraints validated. Throws on mismatch.
examples/src/protobuf/decode.ts
import typia, { tags } from "typia"; const member: IMember = typia.random<IMember>(); const encoded: Uint8Array = typia.protobuf.encode<IMember>(member); const decoded: IMember = typia.protobuf.decode<IMember>(encoded); console.log(member, decoded); interface IMember { id: | (string & tags.Sequence<11>) | (number & tags.Type<"uint64"> & tags.Sequence<12>) | (Uint8Array & tags.Sequence<13>); name: (string & tags.Sequence<20>) | null; children: Array<IMember> & tags.Sequence<30>; keywords: Map<string, string> & tags.Sequence<40>; thumbnail: | (string & tags.Format<"uri"> & tags.ContentMediaType<"image/*">) | Uint8Array; email: string & tags.Format<"email">; hobbies: Array<IHobby>; } interface IHobby { id: string & tags.Format<"uuid">; name: string; valid: boolean; }

Variants

FunctionValidates result?On failure
protobuf.decode<T>Nooutput is whatever fell out of the binary reader
protobuf.isDecode<T>Yes (is)returns null
protobuf.assertDecode<T>Yes (assert)throws TypeGuardError
protobuf.validateDecode<T>Yes (validate)returns IValidation<Resolved<T>>
Important

What the *Decode validators actually verify.

They check custom tag constraints โ€” tags.Format<"uuid">, tags.Minimum<0>, etc. They do not re-verify that the bytes were structurally valid Protocol Buffer for T โ€” the decoder already did that decoding work. So you can rely on these to catch โ€œthe producer encoded a UUID thatโ€™s actually not a UUIDโ€, but not to tell you that someone fed you random bytes that happen to parse.

The safe pattern is: producer uses protobuf.assertEncode (or validateEncode), consumer uses protobuf.assertDecode (or validateDecode). Then both ends of the wire are checked.

undefined

export namespace protobuf { export function decode<T>(buffer: Uint8Array): Resolved<T>; export function isDecode<T>(buffer: Uint8Array): Resolved<T> | null; export function assertDecode<T>(buffer: Uint8Array): Resolved<T>; export function validateDecode<T>( buffer: Uint8Array, ): IValidation<Resolved<T>>; }

Wire errors

The table above describes what happens when validation fails. A malformed payload is different: the binary reader raises an Error while reading the bytes, before any validator runs. That error propagates out of every variant, including isDecode and validateDecode, so it is not reported as a null or as an unsuccessful IValidation.

Wrap the call in try/catch when the bytes come from an untrusted producer.

try { const user = typia.protobuf.assertDecode<User>(bytes); } catch (error) { // malformed wire bytes, or a failed tag constraint }

string fields are one source of these errors. proto3 requires a string to hold valid UTF-8, so typia rejects a payload containing a lone continuation byte, an overlong encoding, a truncated multi-byte sequence, an encoded surrogate, or an out-of-range code point, instead of substituting U+FFFD replacement characters and returning text the producer never sent.

Use Uint8Array when a field must carry arbitrary octets. It maps to proto3 bytes, which has no encoding requirement and accepts the same octets a string field rejects.

Reusable factories

const decodeUser = typia.protobuf.createAssertDecode<User>();
examples/src/protobuf/createDecode.ts
import typia, { tags } from "typia"; export const decode = typia.protobuf.createDecode<IMember>(); interface IMember { id: | (string & tags.Sequence<11>) | (number & tags.Type<"uint64"> & tags.Sequence<12>) | (Uint8Array & tags.Sequence<13>); name: (string & tags.Sequence<20>) | null; children: Array<IMember> & tags.Sequence<30>; keywords: Map<string, string> & tags.Sequence<40>; thumbnail: | (string & tags.Format<"uri"> & tags.ContentMediaType<"image/*">) | Uint8Array; email: string & tags.Format<"email">; hobbies: Array<IHobby>; } interface IHobby { id: string & tags.Format<"uuid">; name: string; valid: boolean; }

Restrictions

Same as the rest of the protobuf surface โ€” see protobuf.message.

Where to go next

Last updated on