typia.protobuf.*Encode โ TypeScript object โ Protocol Buffer bytes
namespace protobuf {
function encode<T>(input: T): Uint8Array; // no validation
function isEncode<T>(input: T): Uint8Array | null; // is + encode
function assertEncode<T>(input: T): Uint8Array; // assert + encode
function validateEncode<T>(input: T): IValidation<Uint8Array>; // validate + encode
}The encoder reads your type at compile time and emits a hand-rolled binary writer for that exact shape โ no separate .proto schema is needed. You only need protobuf.message when another service has to read the schema.
First example
import typia from "typia";
interface User { id: string; age: number; hobbies: string[] }
const bytes: Uint8Array = typia.protobuf.assertEncode<User>({
id: "1",
age: 25,
hobbies: ["reading"],
});TypeScript Source
import typia, { tags } from "typia";
const member: IMember = typia.random<IMember>();
const byte: Uint8Array = typia.protobuf.encode<IMember>(member);
console.log(byte);
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 input? | On failure |
|---|---|---|
protobuf.encode<T> | No | output is undefined โ typically the bytes will not decode |
protobuf.isEncode<T> | Yes (is) | returns null |
protobuf.assertEncode<T> | Yes (assert) | throws TypeGuardError |
protobuf.validateEncode<T> | Yes (validate) | returns IValidation<Uint8Array> |
protobuf.encode<T> trusts you completely.
If input doesnโt actually match T, the encoder writes whatever bytes its emitted code happens to produce โ and the decoder on the other end will likely fail or produce garbage. Use it only when the input was constructed inside the same call frame from typed values. Otherwise, pick assertEncode or validateEncode.
undefined
export namespace protobuf {
export function encode<T>(input: T): Uint8Array;
export function isEncode<T>(input: T): Uint8Array | null;
export function assertEncode<T>(input: T): Uint8Array;
export function validateEncode<T>(input: T): IValidation<Uint8Array>;
}Reusable factories
Same pattern as the other namespaces โ hoist the per-type code once:
const encodeUser = typia.protobuf.createAssertEncode<User>();TypeScript Source
import typia, { tags } from "typia";
export const encode = typia.protobuf.createEncode<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
The encoder follows the same type restrictions as protobuf.message: top-level type must be a single static object, no two-dimensional containers, no any/Date/Set/etc.
If you need numeric types Protocol Buffer specifies but TypeScript doesnโt (e.g. uint32, int64), pick them with type tags on the property:
interface Pricing {
cents: number & tags.Type<"uint32">;
customerCount: bigint & tags.Type<"uint64">;
}Where to go next
- Decoding the bytes back into a value โ
protobuf.decode - Sharing the schema with another language โ
protobuf.message - Numeric tags โ Special Tags