Skip to Content

typia.llm.schema โ€” schema for a single inner type

signature
namespace llm { function schema< T, Config extends Partial<ILlmSchema.IConfig> = {}, >( $defs: Record<string, ILlmSchema>, ): ILlmSchema; }

typia.llm.schema<T> generates an ILlmSchema for T โ€” useful when youโ€™re composing schemas by hand instead of letting parameters or application do the whole thing.

You pass a $defs object as the runtime argument. Any named types referenced in T will be added to $defs and surfaced through $ref. So you can call llm.schema multiple times against the same $defs and the referenced sub-schemas will be deduplicated.

Most users want parameters, structuredOutput, or application โ€” they all generate full top-level schemas for you. schema is the building block.

First example

hello-schema.ts
import typia from "typia"; import { ILlmSchema } from "typia"; interface Animal { name: string; legs: number; } const $defs: Record<string, ILlmSchema> = {}; const s = typia.llm.schema<Animal>($defs); // s is `{ "$ref": "#/$defs/Animal" }` // $defs.Animal = { type: "object", properties: { name: ..., legs: ... }, ... }

undefined

typia
export namespace llm { export function schema< T, Config extends Partial<ILlmSchema.IConfig> = {}, >( $defs: Record<string, ILlmSchema>, ): ILlmSchema; }
examples/src/llm/schema.ts
import typia, { ILlmSchema, tags } from "typia"; export const $defs: Record<string, ILlmSchema> = {}; export const schema: ILlmSchema = typia.llm.schema<IBbsArticle>($defs); /** * Article entity. * * `IBbsArticle` is an entity representing an article in the BBS (Bulletin Board * System). */ interface IBbsArticle { /** Primary Key. */ id: string & tags.Format<"uuid">; /** * Title of the article. * * Representative title of the article. */ title: string; /** * Content body. * * Content body of the article writtn in the markdown format. */ body: string; /** * Thumbnail image URI. * * Thumbnail image URI which can represent the article. * * If configured as `null`, it means that no thumbnail image in the article. */ thumbnail: | null | (string & tags.Format<"uri"> & tags.ContentMediaType<"image/*">); /** Creation time of the article. */ created_at: string & tags.Format<"date-time">; /** Last updated time of the article. */ updated_at: string & tags.Format<"date-time">; }

Special fields

Type tags carry over to the JSON Schema:

  • tags.MaxLength<100> โ†’ "maxLength": 100
  • tags.Format<"email"> โ†’ "format": "email"
  • tags.Minimum<0> โ†’ "minimum": 0

JSDoc comments on properties become "description". Two extra comment tags only affect the emitted schema (not runtime validation):

TagEffect
@title SomethingSets "title" separately from the description
@deprecatedSets "deprecated": true
@hidden / @internalExcludes the field from the emitted schema
examples/src/llm/schema-special.ts
import typia, { ILlmSchema, tags } from "typia"; export const $defs: Record<string, ILlmSchema> = {}; export const schema: ILlmSchema = typia.llm.schema<Special>($defs); interface Special { /** * Deprecated tags are just used for marking. * * @deprecated * @title Unsigned integer */ type: number & tags.Type<"int32">; /** * Internal tagged property never be shown in JSON schema. * * It even doesn't be shown in other `typia` functions like `assert<T>()`. * * @internal */ internal: number[]; /** * Hidden tagged property never be shown in JSON schema. * * However, it would be shown in other `typia` functions like * `stringify<T>()`. * * @ignore */ hidden: boolean; /** * You can limit the range of number. * * @exclusiveMinimum 19 * @maximum 100 */ number?: number; /** * You can limit the length of string. * * Also, multiple range conditions are also possible. */ string: string & ( | (tags.MinLength<3> & tags.MaxLength<24>) | (tags.MinLength<40> & tags.MaxLength<100>) ); /** * You can limit the pattern of string. * * @pattern ^[a-z]+$ */ pattern: string; /** * You can limit the format of string. * * @format date-time */ format: string | null; /** In the Array case, possible to restrict its elements. */ array: Array<string & tags.Format<"uuid">> & tags.MinItems<3>; }

Custom fields

JSON Schema lets you add x-โ€ฆ extensions. typia surfaces them through tags.TagBase.schema (and the tags.JsonSchemaPlugin shortcut):

examples/src/llm/schema-custom.ts
import typia, { ILlmSchema, tags } from "typia"; export const $defs: Record<string, ILlmSchema> = {}; export const schema: ILlmSchema = typia.llm.schema<IAccount>($defs); type Monetary<Value extends string> = tags.TagBase<{ target: "number"; kind: "monetary"; value: Value; schema: { "x-monetary": Value; }; }>; type Placeholder<Value extends string> = tags.JsonSchemaPlugin<{ "x-placeholder": Value; }>; interface IAccount { code: string & Placeholder<"Write you account code please">; balance: number & Monetary<"dollar">; }

Restrictions

LLM schemas are OpenAPI 3.0-style JSON Schema. A few things donโ€™t survive the conversion:

No bigint

Same as standard JSON Schema. bigint properties cause a compile error.

No tuples

[number, string] is not allowed โ€” no LLM provider supports tuples, and they confuse applicationโ€™s function-grouping logic. Replace tuples with a plain object: { count: number; name: string }.

src/examples/llm.schema.bigint-and-tuple.ts
import typia from "typia"; typia.llm.schema<bigint>({}); typia.llm.schema<[number, string]>({});

No dynamic object keys

Record<string, T> is not allowed. Convert it to an array of { key, value } pairs:

// not allowed typia.llm.schema<Record<string, number>>({}); // recommended typia.llm.schema<Array<{ key: string; value: number }>>({});
src/examples/llm.schema.additionalProperties.ts
import typia from "typia"; typia.llm.schema<Record<string, number>>({});

Recursion is bounded

LLM providers have limits on how deep a recursive schema can go. typia handles recursion as follows:

  • A type that recurses through an array is expanded 3 times; the 4th level is removed from the array.
  • A type that recurses through an optional property is expanded 3 times; the 4th level drops the property.
  • A type that recurses through an anyOf is removed from that branch.
examples/src/llm/schema-recursive-gemini.ts
import typia, { ILlmSchema, tags } from "typia"; const $defs: Record<string, ILlmSchema> = {}; typia.llm.schema<IDepartment>($defs); interface IDepartment { id: string & tags.Format<"uuid">; name: string; department: IDepartment[]; }

Where to go next

Last updated on