encode()
functions
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>;
}
undefined
/**
* Custom error class thrown when runtime assertion fails in `typia.assert<T>()` function.
*
* This error is thrown by the `typia.assert<T>()` function when the input value
* doesn't match the expected type.
*
* The error provides detailed information about the first assertion failure encountered,
* including the access path where the error occurred, the expected type, and the actual value.
*
* @template T - The expected type (generic for type safety)
* @author Jeongho Nam - https://github.com/samchon
* @example
* ```typescript
* interface IMember {
* name: string;
* age: number & ExclusiveMinimum<19>;
* }
*
* try {
* typia.assert<IMember>({ name: "John", age: 18 });
* } catch (error) {
* if (error instanceof TypeGuardError) {
* console.log(error.method); // "typia.assert"
* console.log(error.path); // "input.age"
* console.log(error.expected); // "number & ExclusiveMinimum<19>"
* console.log(error.value); // 18
* }
* }
* ```
*/
export class TypeGuardError<T = any> extends Error {
/**
* The name of the typia method that threw this error.
*
* @example "typia.assert"
*/
public readonly method: string;
/**
* The access path to the property where the assertion error occurred.
*
* Uses dot notation to indicate the path for nested object properties.
* May be `undefined` if the error occurred at the root level.
*
* @example
* - `"input.age"` - Error in the age property of the object
* - `"input.profile.email"` - Error in the email property of a nested object
* - `"input[0].name"` - Error in the name property of the first array element
* - `undefined` - Error occurred at the root level
*/
public readonly path: string | undefined;
/**
* String representation of the expected type at the error location.
*
* Represents TypeScript types as strings, including detailed type information
* for complex types.
*
* @example
* - `"string"` - Expected string type
* - `"number & ExclusiveMinimum<19>"` - Expected number greater than 19
* - `"undefined"` - Expected undefined (when superfluous property found in assertion)
* - `"{ name: string; age: number }"` - Expected object type
*/
public readonly expected: string;
/**
* The actual value that failed assertion.
*
* Stores the actual value at the error path as-is.
* Useful for debugging by comparing the expected type with the actual value.
*
* @example
* - `18` - Numeric value
* - `"invalid"` - String value
* - `{ name: "John", age: 18, sex: 1 }` - Object value
*/
public readonly value: any;
/**
* Phantom property for type safety purposes.
*
* This property is not actually used and exists only to maintain
* the generic type T in TypeScript's type system.
* Always has an `undefined` value at runtime.
*
* @internal
*/
protected readonly fake_expected_typed_value_?: T | undefined;
/**
* Creates a new TypeGuardError instance.
*
* @param props - Object containing the properties needed to create the error
*
* @example
* ```typescript
* const error = new TypeGuardError({
* method: "typia.assert",
* path: "input.age",
* expected: "number & ExclusiveMinimum<19>",
* value: 18
* });
* ```
*/
public constructor(props: TypeGuardError.IProps) {
// MESSAGE CONSTRUCTION
// Use custom message if provided, otherwise generate default format
super(
props.message ||
`Error on ${props.method}(): invalid type${
props.path ? ` on ${props.path}` : ""
}, expect to be ${props.expected}`,
);
// INHERITANCE POLYFILL
// Set up prototype for compatibility across different JavaScript environments
const proto = new.target.prototype;
if (Object.setPrototypeOf) Object.setPrototypeOf(this, proto);
else (this as any).__proto__ = proto;
// ASSIGN MEMBERS
this.method = props.method;
this.path = props.path;
this.expected = props.expected;
this.value = props.value;
}
}
export namespace TypeGuardError {
/**
* Interface for properties passed to the TypeGuardError constructor.
*
* @example
* ```typescript
* const props: TypeGuardError.IProps = {
* method: "typia.assertEquals",
* path: "input.sex",
* expected: "undefined",
* value: 1,
* message: "Custom error message" // optional
* };
* ```
*/
export interface IProps {
/**
* The name of the typia method that threw the error.
*
* @example "typia.assert", "typia.assertEquals"
*/
method: string;
/**
* The access path to the property where the assertion error occurred (optional).
*
* @example "input.age", "input.profile.email"
*/
path?: undefined | string;
/**
* String representation of the expected type at the error location.
*
* @example "string", "number & ExclusiveMinimum<19>"
*/
expected: string;
/**
* The actual value that failed assertion.
*/
value: any;
/**
* Custom error message (optional).
*
* If not provided, a default format message will be automatically generated.
*/
message?: undefined | string;
}
}
undefined
/**
* Union type representing the result of type validation
*
* This is the return type of {@link typia.validate} functions, returning
* {@link IValidation.ISuccess} on validation success and
* {@link IValidation.IFailure} on validation failure. When validation fails, it
* provides detailed, granular error information that precisely describes what
* went wrong, where it went wrong, and what was expected.
*
* This comprehensive error reporting makes `IValidation` particularly valuable
* for AI function calling scenarios, where Large Language Models (LLMs) need
* specific feedback to correct their parameter generation. The detailed error
* information is used by ILlmFunction.validate() to provide validation feedback
* to AI agents, enabling iterative correction and improvement of function
* calling accuracy.
*
* This type uses the Discriminated Union pattern, allowing type specification
* through the success property:
*
* ```typescript
* const result = typia.validate<string>(input);
* if (result.success) {
* // IValidation.ISuccess<string> type
* console.log(result.data); // validated data accessible
* } else {
* // IValidation.IFailure type
* console.log(result.errors); // detailed error information accessible
* }
* ```
*
* @author Jeongho Nam - https://github.com/samchon
* @template T The type to validate
*/
export type IValidation<T = unknown> =
| IValidation.ISuccess<T>
| IValidation.IFailure;
export namespace IValidation {
/**
* Interface returned when type validation succeeds
*
* Returned when the input value perfectly conforms to the specified type T.
* Since success is true, TypeScript's type guard allows safe access to the
* validated data through the data property.
*
* @template T The validated type
*/
export interface ISuccess<T = unknown> {
/** Indicates validation success */
success: true;
/** The validated data of type T */
data: T;
}
/**
* Interface returned when type validation fails
*
* Returned when the input value does not conform to the expected type.
* Contains comprehensive error information designed to be easily understood
* by both humans and AI systems. Each error in the errors array provides
* precise details about validation failures, including the exact path to the
* problematic property, what type was expected, and what value was actually
* provided.
*
* This detailed error structure is specifically optimized for AI function
* calling validation feedback. When LLMs make type errors during function
* calling, these granular error reports enable the AI to understand exactly
* what went wrong and how to fix it, improving success rates in subsequent
* attempts.
*
* Example error scenarios:
*
* - Type mismatch: expected "string" but got number 5
* - Format violation: expected "string & Format<'uuid'>" but got
* "invalid-format"
* - Missing properties: expected "required property 'name'" but got undefined
* - Array type errors: expected "Array<string>" but got single string value
*
* The errors are used by ILlmFunction.validate() to provide structured
* feedback to AI agents, enabling them to correct their parameter generation
* and achieve improved function calling accuracy.
*/
export interface IFailure {
/** Indicates validation failure */
success: false;
/** The original input data that failed validation */
data: unknown;
/** Array of detailed validation errors */
errors: IError[];
}
/**
* Detailed information about a specific validation error
*
* Each error provides granular, actionable information about validation
* failures, designed to be immediately useful for both human developers and
* AI systems. The error structure follows a consistent format that enables
* precise identification and correction of type mismatches.
*
* This error format is particularly valuable for AI function calling
* scenarios, where LLMs need to understand exactly what went wrong to
* generate correct parameters. The combination of path, expected type, and
* actual value provides the AI with sufficient context to make accurate
* corrections, which is why ILlmFunction.validate() can achieve such high
* success rates in validation feedback loops.
*
* Real-world examples from AI function calling:
*
* {
* path: "input.member.age",
* expected: "number & Format<'uint32'>",
* value: 20.75 // AI provided float instead of uint32
* }
*
* {
* path: "input.categories",
* expected: "Array<string>",
* value: "technology" // AI provided string instead of array
* }
*
* {
* path: "input.id",
* expected: "string & Format<'uuid'>",
* value: "invalid-uuid-format" // AI provided malformed UUID
* }
*/
export interface IError {
/**
* The path to the property that failed validation (e.g.,
* "input.member.age")
*/
path: string;
/** Description of the expected type or format */
expected: string;
/** The actual value that caused the validation failure */
value: any;
}
}
undefined
import { Equal } from "./typings/Equal";
import { IsTuple } from "./typings/IsTuple";
import { NativeClass } from "./typings/NativeClass";
import { ValueOf } from "./typings/ValueOf";
/**
* Resolved type erased every methods.
*
* `Resolved` is a type of TMP (Type Meta Programming) type which converts
* its argument as a resolved type that erased every method properties.
*
* If the target argument is a built-in class which returns its origin primitive type
* through the `valueOf()` method like the `String` or `Number`, its return type would
* be the `string` or `number`. Otherwise, the built-in class does not have the
* `valueOf()` method, the return type would be same with the target argument.
*
* Otherwise, the target argument is a type of custom class, all of its custom methods
* would be erased and its prototype would be changed to the primitive `object`.
* Therefore, return type of the TMP type finally be the resolved object.
*
* Before | After
* ------------------------|----------------------------------------
* `Boolean` | `boolean`
* `Number` | `number`
* `BigInt` | `bigint`
* `String` | `string`
* `Class` | `interface`
* Native Class or Others | No change
*
* @template T Target argument type.
* @author Jeongho Nam - https://github.com/samchon
* @author Kyungsu Kang - https://github.com/kakasoo
*/
export type Resolved<T> =
Equal<T, ResolvedMain<T>> extends true ? T : ResolvedMain<T>;
type ResolvedMain<T> = T extends [never]
? never // (special trick for jsonable | null) type
: ValueOf<T> extends boolean | number | bigint | string
? ValueOf<T>
: T extends Function
? never
: T extends object
? ResolvedObject<T>
: ValueOf<T>;
type ResolvedObject<T extends object> =
T extends Array<infer U>
? IsTuple<T> extends true
? ResolvedTuple<T>
: ResolvedMain<U>[]
: T extends Set<infer U>
? Set<ResolvedMain<U>>
: T extends Map<infer K, infer V>
? Map<ResolvedMain<K>, ResolvedMain<V>>
: T extends WeakSet<any> | WeakMap<any, any>
? never
: T extends NativeClass
? T
: {
[P in keyof T]: ResolvedMain<T[P]>;
};
type ResolvedTuple<T extends readonly any[]> = T extends []
? []
: T extends [infer F]
? [ResolvedMain<F>]
: T extends [infer F, ...infer Rest extends readonly any[]]
? [ResolvedMain<F>, ...ResolvedTuple<Rest>]
: T extends [(infer F)?]
? [ResolvedMain<F>?]
: T extends [(infer F)?, ...infer Rest extends readonly any[]]
? [ResolvedMain<F>?, ...ResolvedTuple<Rest>]
: [];
Protocol Buffer Encoder.
You can easily convert a JavaScript object to a binary data of Protocol Buffer, without any extra Protocol Buffer Message Schema definition. typia.protobuf.encode<T>()
function analyzes your type T
, and generates a Protocol Buffer Message Schema internally. And then, it converts the input
instance to the binary data of Protocol Buffer format.
By the way, typia.protobuf.encode<T>()
function does not validate the input
value. It just believes user and input
value, and converts to the Protocol Buffer binary data directly without any validation. By the way, if the input
value was not validate, the encoded binary data never can be decoded. So, if you can’t sure the input
value type, you should use below functions instead.
typia.protobuf.isEncode<T>()
:typia.is<T>()
+typia.protobuf.encode<T>()
typia.protobuf.assertEncode<T>()
:typia.assert<T>()
+typia.protobuf.encode<T>()
typia.protobuf.validateEncode<T>()
:typia.validate<T>()
+typia.protobuf.encode<T>()
AOT compilation
typia.protobuf.encode<T>()
and other similar functions are still much faster than any other competitive libraries, even though they include type checking process. This is the power of AOT compilation, writing optimal dedicated code by analyzing TypeScript type, in the compilation level.
TypeScript Source Code
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;
}
Compiled JavaScript File
import typia from "typia";
import * as __typia_transform__ProtobufSizer from "typia/lib/internal/_ProtobufSizer.js";
import * as __typia_transform__ProtobufWriter from "typia/lib/internal/_ProtobufWriter.js";
import * as __typia_transform__isFormatEmail from "typia/lib/internal/_isFormatEmail.js";
import * as __typia_transform__isFormatUri from "typia/lib/internal/_isFormatUri.js";
import * as __typia_transform__isFormatUuid from "typia/lib/internal/_isFormatUuid.js";
import * as __typia_transform__isTypeUint64 from "typia/lib/internal/_isTypeUint64.js";
import * as __typia_transform__randomArray from "typia/lib/internal/_randomArray.js";
import * as __typia_transform__randomBoolean from "typia/lib/internal/_randomBoolean.js";
import * as __typia_transform__randomFormatEmail from "typia/lib/internal/_randomFormatEmail.js";
import * as __typia_transform__randomFormatUri from "typia/lib/internal/_randomFormatUri.js";
import * as __typia_transform__randomFormatUuid from "typia/lib/internal/_randomFormatUuid.js";
import * as __typia_transform__randomInteger from "typia/lib/internal/_randomInteger.js";
import * as __typia_transform__randomPick from "typia/lib/internal/_randomPick.js";
import * as __typia_transform__randomString from "typia/lib/internal/_randomString.js";
import * as __typia_transform__throwTypeGuardError from "typia/lib/internal/_throwTypeGuardError.js";
const member = (() => {
const _ro0 = (_recursive = true, _depth = 0) => ({
id: __typia_transform__randomPick._randomPick([
() =>
(_generator?.string ?? __typia_transform__randomString._randomString)({
type: "string",
"x-protobuf-sequence": 11,
}),
() =>
(
_generator?.integer ?? __typia_transform__randomInteger._randomInteger
)({
type: "integer",
minimum: 0,
"x-protobuf-sequence": 12,
}),
() =>
new Uint8Array(
5 >= _depth
? (
_generator?.array ?? __typia_transform__randomArray._randomArray
)({
type: "array",
element: () =>
(
_generator?.integer ??
__typia_transform__randomInteger._randomInteger
)({
type: "integer",
minimum: 0,
maximum: 255,
}),
})
: [],
),
])(),
name: __typia_transform__randomPick._randomPick([
() => null,
() =>
(_generator?.string ?? __typia_transform__randomString._randomString)({
type: "string",
"x-protobuf-sequence": 20,
}),
])(),
children:
5 >= _depth
? (_generator?.array ?? __typia_transform__randomArray._randomArray)({
type: "array",
"x-protobuf-sequence": 30,
element: () => _ro0(true, _recursive ? 1 + _depth : _depth),
})
: [],
keywords: new Map(
5 >= _depth
? (_generator?.array ?? __typia_transform__randomArray._randomArray)({
type: "array",
element: () => [
(
_generator?.string ??
__typia_transform__randomString._randomString
)({
type: "string",
}),
(
_generator?.string ??
__typia_transform__randomString._randomString
)({
type: "string",
}),
],
})
: [],
),
thumbnail: __typia_transform__randomPick._randomPick([
() =>
(
_generator?.uri ?? __typia_transform__randomFormatUri._randomFormatUri
)(),
() =>
new Uint8Array(
5 >= _depth
? (
_generator?.array ?? __typia_transform__randomArray._randomArray
)({
type: "array",
element: () =>
(
_generator?.integer ??
__typia_transform__randomInteger._randomInteger
)({
type: "integer",
minimum: 0,
maximum: 255,
}),
})
: [],
),
])(),
email: (
_generator?.email ??
__typia_transform__randomFormatEmail._randomFormatEmail
)(),
hobbies:
5 >= _depth
? (_generator?.array ?? __typia_transform__randomArray._randomArray)({
type: "array",
element: () => _ro1(true, _recursive ? 1 + _depth : _depth),
})
: [],
});
const _ro1 = (_recursive = false, _depth = 0) => ({
id: (
_generator?.uuid ?? __typia_transform__randomFormatUuid._randomFormatUuid
)(),
name: (_generator?.string ?? __typia_transform__randomString._randomString)(
{
type: "string",
},
),
valid: (
_generator?.boolean ?? __typia_transform__randomBoolean._randomBoolean
)({
type: "boolean",
}),
});
let _generator;
return (generator) => {
_generator = generator;
return _ro0();
};
})()();
const byte = (() => {
const encoder = (writer, input) => {
const _peo0 = (input) => {
// property "id": ((Uint8Array & Sequence<13>) | (number & Type<"uint64"> & Sequence<12>) | (string & Sequence<11>));
if (input.id instanceof Uint8Array) {
writer.uint32(106);
writer.bytes(input.id);
} else if ("number" === typeof input.id) {
writer.uint32(96);
writer.uint64(input.id);
} else if ("string" === typeof input.id) {
writer.uint32(90);
writer.string(input.id);
} else
__typia_transform__throwTypeGuardError._throwTypeGuardError({
method: "typia.protobuf.encode",
expected:
'((Uint8Array & Sequence<13>) | (number & Type<"uint64"> & Sequence<12>) | (string & Sequence<11>))',
value: input.id,
});
// property "name": ((string & Sequence<20>) | null);
if (null !== input.name) {
writer.uint32(162);
writer.string(input.name);
}
// property "children": (Array<IMember> & Sequence<30>);
if (0 !== input.children.length) {
for (const elem of input.children) {
writer.uint32(242);
writer.fork();
_peo0(elem);
writer.ldelim();
}
}
// property "keywords": (Map<string, string> & Sequence<40>);
for (const [key, value] of input.keywords) {
writer.uint32(322);
writer.fork();
writer.uint32(10);
writer.string(key);
writer.uint32(18);
writer.string(value);
writer.ldelim();
}
// property "thumbnail": ((string & Format<"uri"> & ContentMediaType<"image/*">) | Uint8Array);
if (input.thumbnail instanceof Uint8Array) {
writer.uint32(330);
writer.bytes(input.thumbnail);
} else if ("string" === typeof input.thumbnail) {
writer.uint32(338);
writer.string(input.thumbnail);
} else
__typia_transform__throwTypeGuardError._throwTypeGuardError({
method: "typia.protobuf.encode",
expected:
'((string & Format<"uri"> & ContentMediaType<"image/*">) | Uint8Array)',
value: input.thumbnail,
});
// property "email": (string & Format<"email">);
writer.uint32(346);
writer.string(input.email);
// property "hobbies": Array<IHobby>;
if (0 !== input.hobbies.length) {
for (const elem of input.hobbies) {
writer.uint32(354);
writer.fork();
_peo1(elem);
writer.ldelim();
}
}
};
const _peo1 = (input) => {
// property "id": (string & Format<"uuid">);
writer.uint32(10);
writer.string(input.id);
// property "name": string;
writer.uint32(18);
writer.string(input.name);
// property "valid": boolean;
writer.uint32(24);
writer.bool(input.valid);
};
const _io0 = (input) =>
null !== input.id &&
undefined !== input.id &&
("string" === typeof input.id ||
("number" === typeof input.id &&
__typia_transform__isTypeUint64._isTypeUint64(input.id)) ||
input.id instanceof Uint8Array) &&
(null === input.name || "string" === typeof input.name) &&
Array.isArray(input.children) &&
input.children.every(
(elem) => "object" === typeof elem && null !== elem && _io0(elem),
) &&
input.keywords instanceof Map &&
(() =>
[...input.keywords].every(
(elem) =>
Array.isArray(elem) &&
elem.length === 2 &&
"string" === typeof elem[0] &&
"string" === typeof elem[1],
))() &&
null !== input.thumbnail &&
undefined !== input.thumbnail &&
(("string" === typeof input.thumbnail &&
__typia_transform__isFormatUri._isFormatUri(input.thumbnail)) ||
input.thumbnail instanceof Uint8Array) &&
"string" === typeof input.email &&
__typia_transform__isFormatEmail._isFormatEmail(input.email) &&
Array.isArray(input.hobbies) &&
input.hobbies.every(
(elem) => "object" === typeof elem && null !== elem && _io1(elem),
);
const _io1 = (input) =>
"string" === typeof input.id &&
__typia_transform__isFormatUuid._isFormatUuid(input.id) &&
"string" === typeof input.name &&
"boolean" === typeof input.valid;
_peo0(input);
return writer;
};
return (input) => {
const sizer = encoder(
new __typia_transform__ProtobufSizer._ProtobufSizer(),
input,
);
const writer = encoder(
new __typia_transform__ProtobufWriter._ProtobufWriter(sizer),
input,
);
return writer.buffer();
};
})()(member);
console.log(byte);
Reusable Functions
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>;
}
undefined
/**
* Custom error class thrown when runtime assertion fails in `typia.assert<T>()` function.
*
* This error is thrown by the `typia.assert<T>()` function when the input value
* doesn't match the expected type.
*
* The error provides detailed information about the first assertion failure encountered,
* including the access path where the error occurred, the expected type, and the actual value.
*
* @template T - The expected type (generic for type safety)
* @author Jeongho Nam - https://github.com/samchon
* @example
* ```typescript
* interface IMember {
* name: string;
* age: number & ExclusiveMinimum<19>;
* }
*
* try {
* typia.assert<IMember>({ name: "John", age: 18 });
* } catch (error) {
* if (error instanceof TypeGuardError) {
* console.log(error.method); // "typia.assert"
* console.log(error.path); // "input.age"
* console.log(error.expected); // "number & ExclusiveMinimum<19>"
* console.log(error.value); // 18
* }
* }
* ```
*/
export class TypeGuardError<T = any> extends Error {
/**
* The name of the typia method that threw this error.
*
* @example "typia.assert"
*/
public readonly method: string;
/**
* The access path to the property where the assertion error occurred.
*
* Uses dot notation to indicate the path for nested object properties.
* May be `undefined` if the error occurred at the root level.
*
* @example
* - `"input.age"` - Error in the age property of the object
* - `"input.profile.email"` - Error in the email property of a nested object
* - `"input[0].name"` - Error in the name property of the first array element
* - `undefined` - Error occurred at the root level
*/
public readonly path: string | undefined;
/**
* String representation of the expected type at the error location.
*
* Represents TypeScript types as strings, including detailed type information
* for complex types.
*
* @example
* - `"string"` - Expected string type
* - `"number & ExclusiveMinimum<19>"` - Expected number greater than 19
* - `"undefined"` - Expected undefined (when superfluous property found in assertion)
* - `"{ name: string; age: number }"` - Expected object type
*/
public readonly expected: string;
/**
* The actual value that failed assertion.
*
* Stores the actual value at the error path as-is.
* Useful for debugging by comparing the expected type with the actual value.
*
* @example
* - `18` - Numeric value
* - `"invalid"` - String value
* - `{ name: "John", age: 18, sex: 1 }` - Object value
*/
public readonly value: any;
/**
* Phantom property for type safety purposes.
*
* This property is not actually used and exists only to maintain
* the generic type T in TypeScript's type system.
* Always has an `undefined` value at runtime.
*
* @internal
*/
protected readonly fake_expected_typed_value_?: T | undefined;
/**
* Creates a new TypeGuardError instance.
*
* @param props - Object containing the properties needed to create the error
*
* @example
* ```typescript
* const error = new TypeGuardError({
* method: "typia.assert",
* path: "input.age",
* expected: "number & ExclusiveMinimum<19>",
* value: 18
* });
* ```
*/
public constructor(props: TypeGuardError.IProps) {
// MESSAGE CONSTRUCTION
// Use custom message if provided, otherwise generate default format
super(
props.message ||
`Error on ${props.method}(): invalid type${
props.path ? ` on ${props.path}` : ""
}, expect to be ${props.expected}`,
);
// INHERITANCE POLYFILL
// Set up prototype for compatibility across different JavaScript environments
const proto = new.target.prototype;
if (Object.setPrototypeOf) Object.setPrototypeOf(this, proto);
else (this as any).__proto__ = proto;
// ASSIGN MEMBERS
this.method = props.method;
this.path = props.path;
this.expected = props.expected;
this.value = props.value;
}
}
export namespace TypeGuardError {
/**
* Interface for properties passed to the TypeGuardError constructor.
*
* @example
* ```typescript
* const props: TypeGuardError.IProps = {
* method: "typia.assertEquals",
* path: "input.sex",
* expected: "undefined",
* value: 1,
* message: "Custom error message" // optional
* };
* ```
*/
export interface IProps {
/**
* The name of the typia method that threw the error.
*
* @example "typia.assert", "typia.assertEquals"
*/
method: string;
/**
* The access path to the property where the assertion error occurred (optional).
*
* @example "input.age", "input.profile.email"
*/
path?: undefined | string;
/**
* String representation of the expected type at the error location.
*
* @example "string", "number & ExclusiveMinimum<19>"
*/
expected: string;
/**
* The actual value that failed assertion.
*/
value: any;
/**
* Custom error message (optional).
*
* If not provided, a default format message will be automatically generated.
*/
message?: undefined | string;
}
}
undefined
/**
* Union type representing the result of type validation
*
* This is the return type of {@link typia.validate} functions, returning
* {@link IValidation.ISuccess} on validation success and
* {@link IValidation.IFailure} on validation failure. When validation fails, it
* provides detailed, granular error information that precisely describes what
* went wrong, where it went wrong, and what was expected.
*
* This comprehensive error reporting makes `IValidation` particularly valuable
* for AI function calling scenarios, where Large Language Models (LLMs) need
* specific feedback to correct their parameter generation. The detailed error
* information is used by ILlmFunction.validate() to provide validation feedback
* to AI agents, enabling iterative correction and improvement of function
* calling accuracy.
*
* This type uses the Discriminated Union pattern, allowing type specification
* through the success property:
*
* ```typescript
* const result = typia.validate<string>(input);
* if (result.success) {
* // IValidation.ISuccess<string> type
* console.log(result.data); // validated data accessible
* } else {
* // IValidation.IFailure type
* console.log(result.errors); // detailed error information accessible
* }
* ```
*
* @author Jeongho Nam - https://github.com/samchon
* @template T The type to validate
*/
export type IValidation<T = unknown> =
| IValidation.ISuccess<T>
| IValidation.IFailure;
export namespace IValidation {
/**
* Interface returned when type validation succeeds
*
* Returned when the input value perfectly conforms to the specified type T.
* Since success is true, TypeScript's type guard allows safe access to the
* validated data through the data property.
*
* @template T The validated type
*/
export interface ISuccess<T = unknown> {
/** Indicates validation success */
success: true;
/** The validated data of type T */
data: T;
}
/**
* Interface returned when type validation fails
*
* Returned when the input value does not conform to the expected type.
* Contains comprehensive error information designed to be easily understood
* by both humans and AI systems. Each error in the errors array provides
* precise details about validation failures, including the exact path to the
* problematic property, what type was expected, and what value was actually
* provided.
*
* This detailed error structure is specifically optimized for AI function
* calling validation feedback. When LLMs make type errors during function
* calling, these granular error reports enable the AI to understand exactly
* what went wrong and how to fix it, improving success rates in subsequent
* attempts.
*
* Example error scenarios:
*
* - Type mismatch: expected "string" but got number 5
* - Format violation: expected "string & Format<'uuid'>" but got
* "invalid-format"
* - Missing properties: expected "required property 'name'" but got undefined
* - Array type errors: expected "Array<string>" but got single string value
*
* The errors are used by ILlmFunction.validate() to provide structured
* feedback to AI agents, enabling them to correct their parameter generation
* and achieve improved function calling accuracy.
*/
export interface IFailure {
/** Indicates validation failure */
success: false;
/** The original input data that failed validation */
data: unknown;
/** Array of detailed validation errors */
errors: IError[];
}
/**
* Detailed information about a specific validation error
*
* Each error provides granular, actionable information about validation
* failures, designed to be immediately useful for both human developers and
* AI systems. The error structure follows a consistent format that enables
* precise identification and correction of type mismatches.
*
* This error format is particularly valuable for AI function calling
* scenarios, where LLMs need to understand exactly what went wrong to
* generate correct parameters. The combination of path, expected type, and
* actual value provides the AI with sufficient context to make accurate
* corrections, which is why ILlmFunction.validate() can achieve such high
* success rates in validation feedback loops.
*
* Real-world examples from AI function calling:
*
* {
* path: "input.member.age",
* expected: "number & Format<'uint32'>",
* value: 20.75 // AI provided float instead of uint32
* }
*
* {
* path: "input.categories",
* expected: "Array<string>",
* value: "technology" // AI provided string instead of array
* }
*
* {
* path: "input.id",
* expected: "string & Format<'uuid'>",
* value: "invalid-uuid-format" // AI provided malformed UUID
* }
*/
export interface IError {
/**
* The path to the property that failed validation (e.g.,
* "input.member.age")
*/
path: string;
/** Description of the expected type or format */
expected: string;
/** The actual value that caused the validation failure */
value: any;
}
}
undefined
import { Equal } from "./typings/Equal";
import { IsTuple } from "./typings/IsTuple";
import { NativeClass } from "./typings/NativeClass";
import { ValueOf } from "./typings/ValueOf";
/**
* Resolved type erased every methods.
*
* `Resolved` is a type of TMP (Type Meta Programming) type which converts
* its argument as a resolved type that erased every method properties.
*
* If the target argument is a built-in class which returns its origin primitive type
* through the `valueOf()` method like the `String` or `Number`, its return type would
* be the `string` or `number`. Otherwise, the built-in class does not have the
* `valueOf()` method, the return type would be same with the target argument.
*
* Otherwise, the target argument is a type of custom class, all of its custom methods
* would be erased and its prototype would be changed to the primitive `object`.
* Therefore, return type of the TMP type finally be the resolved object.
*
* Before | After
* ------------------------|----------------------------------------
* `Boolean` | `boolean`
* `Number` | `number`
* `BigInt` | `bigint`
* `String` | `string`
* `Class` | `interface`
* Native Class or Others | No change
*
* @template T Target argument type.
* @author Jeongho Nam - https://github.com/samchon
* @author Kyungsu Kang - https://github.com/kakasoo
*/
export type Resolved<T> =
Equal<T, ResolvedMain<T>> extends true ? T : ResolvedMain<T>;
type ResolvedMain<T> = T extends [never]
? never // (special trick for jsonable | null) type
: ValueOf<T> extends boolean | number | bigint | string
? ValueOf<T>
: T extends Function
? never
: T extends object
? ResolvedObject<T>
: ValueOf<T>;
type ResolvedObject<T extends object> =
T extends Array<infer U>
? IsTuple<T> extends true
? ResolvedTuple<T>
: ResolvedMain<U>[]
: T extends Set<infer U>
? Set<ResolvedMain<U>>
: T extends Map<infer K, infer V>
? Map<ResolvedMain<K>, ResolvedMain<V>>
: T extends WeakSet<any> | WeakMap<any, any>
? never
: T extends NativeClass
? T
: {
[P in keyof T]: ResolvedMain<T[P]>;
};
type ResolvedTuple<T extends readonly any[]> = T extends []
? []
: T extends [infer F]
? [ResolvedMain<F>]
: T extends [infer F, ...infer Rest extends readonly any[]]
? [ResolvedMain<F>, ...ResolvedTuple<Rest>]
: T extends [(infer F)?]
? [ResolvedMain<F>?]
: T extends [(infer F)?, ...infer Rest extends readonly any[]]
? [ResolvedMain<F>?, ...ResolvedTuple<Rest>]
: [];
Reusable typia.protobuf.encode<T>()
function generators.
If you repeat to call typia.protobuf.encode<T>()
function on the same type, size of JavaScript files would be larger because of duplicated AOT compilation. To prevent it, you can generate reusable function through typia.protobuf.createEncode<T>()
function.
Just look at the code below, then you may understand how to use it.
TypeScript Source Code
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;
}
Compiled JavaScript File
import typia from "typia";
import * as __typia_transform__ProtobufSizer from "typia/lib/internal/_ProtobufSizer.js";
import * as __typia_transform__ProtobufWriter from "typia/lib/internal/_ProtobufWriter.js";
import * as __typia_transform__isFormatEmail from "typia/lib/internal/_isFormatEmail.js";
import * as __typia_transform__isFormatUri from "typia/lib/internal/_isFormatUri.js";
import * as __typia_transform__isFormatUuid from "typia/lib/internal/_isFormatUuid.js";
import * as __typia_transform__isTypeUint64 from "typia/lib/internal/_isTypeUint64.js";
import * as __typia_transform__throwTypeGuardError from "typia/lib/internal/_throwTypeGuardError.js";
export const encode = (() => {
const encoder = (writer, input) => {
const _peo0 = (input) => {
// property "id": ((Uint8Array & Sequence<13>) | (number & Type<"uint64"> & Sequence<12>) | (string & Sequence<11>));
if (input.id instanceof Uint8Array) {
writer.uint32(106);
writer.bytes(input.id);
} else if ("number" === typeof input.id) {
writer.uint32(96);
writer.uint64(input.id);
} else if ("string" === typeof input.id) {
writer.uint32(90);
writer.string(input.id);
} else
__typia_transform__throwTypeGuardError._throwTypeGuardError({
method: "typia.protobuf.createEncode",
expected:
'((Uint8Array & Sequence<13>) | (number & Type<"uint64"> & Sequence<12>) | (string & Sequence<11>))',
value: input.id,
});
// property "name": ((string & Sequence<20>) | null);
if (null !== input.name) {
writer.uint32(162);
writer.string(input.name);
}
// property "children": (Array<IMember> & Sequence<30>);
if (0 !== input.children.length) {
for (const elem of input.children) {
writer.uint32(242);
writer.fork();
_peo0(elem);
writer.ldelim();
}
}
// property "keywords": (Map<string, string> & Sequence<40>);
for (const [key, value] of input.keywords) {
writer.uint32(322);
writer.fork();
writer.uint32(10);
writer.string(key);
writer.uint32(18);
writer.string(value);
writer.ldelim();
}
// property "thumbnail": ((string & Format<"uri"> & ContentMediaType<"image/*">) | Uint8Array);
if (input.thumbnail instanceof Uint8Array) {
writer.uint32(330);
writer.bytes(input.thumbnail);
} else if ("string" === typeof input.thumbnail) {
writer.uint32(338);
writer.string(input.thumbnail);
} else
__typia_transform__throwTypeGuardError._throwTypeGuardError({
method: "typia.protobuf.createEncode",
expected:
'((string & Format<"uri"> & ContentMediaType<"image/*">) | Uint8Array)',
value: input.thumbnail,
});
// property "email": (string & Format<"email">);
writer.uint32(346);
writer.string(input.email);
// property "hobbies": Array<IHobby>;
if (0 !== input.hobbies.length) {
for (const elem of input.hobbies) {
writer.uint32(354);
writer.fork();
_peo1(elem);
writer.ldelim();
}
}
};
const _peo1 = (input) => {
// property "id": (string & Format<"uuid">);
writer.uint32(10);
writer.string(input.id);
// property "name": string;
writer.uint32(18);
writer.string(input.name);
// property "valid": boolean;
writer.uint32(24);
writer.bool(input.valid);
};
const _io0 = (input) =>
null !== input.id &&
undefined !== input.id &&
("string" === typeof input.id ||
("number" === typeof input.id &&
__typia_transform__isTypeUint64._isTypeUint64(input.id)) ||
input.id instanceof Uint8Array) &&
(null === input.name || "string" === typeof input.name) &&
Array.isArray(input.children) &&
input.children.every(
(elem) => "object" === typeof elem && null !== elem && _io0(elem),
) &&
input.keywords instanceof Map &&
(() =>
[...input.keywords].every(
(elem) =>
Array.isArray(elem) &&
elem.length === 2 &&
"string" === typeof elem[0] &&
"string" === typeof elem[1],
))() &&
null !== input.thumbnail &&
undefined !== input.thumbnail &&
(("string" === typeof input.thumbnail &&
__typia_transform__isFormatUri._isFormatUri(input.thumbnail)) ||
input.thumbnail instanceof Uint8Array) &&
"string" === typeof input.email &&
__typia_transform__isFormatEmail._isFormatEmail(input.email) &&
Array.isArray(input.hobbies) &&
input.hobbies.every(
(elem) => "object" === typeof elem && null !== elem && _io1(elem),
);
const _io1 = (input) =>
"string" === typeof input.id &&
__typia_transform__isFormatUuid._isFormatUuid(input.id) &&
"string" === typeof input.name &&
"boolean" === typeof input.valid;
_peo0(input);
return writer;
};
return (input) => {
const sizer = encoder(
new __typia_transform__ProtobufSizer._ProtobufSizer(),
input,
);
const writer = encoder(
new __typia_transform__ProtobufWriter._ProtobufWriter(sizer),
input,
);
return writer.buffer();
};
})();
References
Protocol Buffer supports special numeric types like int32
or uint64
that are not supported in TypeScript. Also, types of Protocol Buffer cannot fully meet TypeScript type specs either, as expression power of TypeScript types are much stronger than Protocol Buffer.
To know how to define special numeric types like uint64
, and to understand which TypeScript types are not supported in Protocol Buffer specs, it would better to read below documents. I recommend you to read them before using typia.protobuf.encode<T>()
related functions.