typia.protobuf.*Decode โ Protocol Buffer bytes โ TypeScript object
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
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.TypeScript Source
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
| Function | Validates result? | On failure |
|---|---|---|
protobuf.decode<T> | No | output 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>> |
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>();TypeScript Source
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
- Encoding values โ
protobuf.encode - Sharing the schema with other services โ
protobuf.message - Numeric and string tags โ Special Tags