Skip to main content

Magic Types

"Magic Types" is a shorthand for Swagger schemas: instead of a verbose schema object, you write one string that captures the type, an optional format, an example, and whether the field is required.

Both stacks, different reach

On Express, Magic Types describe swaggerModel schemas and _<verb>Swagger types, feeding OpenAPI and type generation. On Bun/Elysia, the same DSL is accepted inside a class's _<verb>Swagger (requestBody, responses, parameters) and the models registry, and expanded into the native OpenAPI document. Either way Magic Types drive documentation only, not request validation (Express uses express-validator, Elysia uses TypeBox). Type generation is Express-only.

Try it

Type a Magic Type below; the OpenAPI schema and TypeScript type update as you go:

type[::format][|example][!|?] · arrays [] · refs @Model

OpenAPI schema
{
  "type": "string",
  "format": "email",
  "example": "john@example.com!"
}

required follows defaultRequiredValueForModels

TypeScript
type T = string;

Syntax

type[::format][|example][!|?]
  • type: A base data type or a reference to another model. Base types are string, number, integer, boolean, array, object, Date, and ObjectId. String formats are date, date-time, password, byte, binary.
  • ::format: (Optional) The format for validation (email, date-time, etc.).
  • |example: (Optional) An example value for documentation.
  • !: (Optional) Marks the field as required (overrides default).
  • ?: (Optional) Marks the field as optional (overrides default).

Examples

Magic TypeDescriptionSwagger Equivalent
stringA simple string{ type: "string" }
string::emailA string with email format{ type: "string", format: "email" }
number!A required number{ type: "number" }, required: true
boolean?An optional boolean{ type: "boolean" }, required: false
string|John DoeA string with an example{ type: "string", example: "John Doe" }
string::email|john@example.comEmail with example{ type: "string", format: "email", example: "john@example.com" }

Arrays

Append [] for an array.

Magic TypeDescriptionSwagger Equivalent
string[]Array of strings{ type: "array", items: { type: "string" } }
number[]!Required array of numbers{ type: "array", items: { type: "number" } }, required: true
@User[]Array of User models{ type: "array", items: { $ref: "#/components/schemas/User" } }

Model References

Reference another schema with @ followed by its name.

Magic TypeDescriptionSwagger Equivalent
@UserReference to User model{ $ref: "#/components/schemas/User" }
@User!Required User reference{ $ref: "#/components/schemas/User" }, required: true
@User?Optional User reference{ $ref: "#/components/schemas/User" }, required: false

Custom Types

Define reusable types in config.customTypes, then use them like any base type.

Configuration

// efesto config
customTypes: {
ObjectId: "string",
Date: { type: "string", format: "date-time" },
Price: { type: "number", format: "float" }
}

Usage

properties: {
id: "ObjectId",
createdAt: "Date",
cost: "Price"
}

A complete model

swaggerModel = {
modelName: "User",
schemas: [
{
name: "User",
properties: {
id: "ObjectId", // Custom type
username: "string!", // Required string
email: "string::email!", // Required email
age: "number?", // Optional number
tags: "string[]", // Array of strings
profile: "@UserProfile", // Reference to another model
createdAt: "Date", // Custom type
},
},
],
};

Nullable Fields

If you have configured defaultNullableOnOptionalFields: true, using the ? operator will also mark the field as nullable: true in the generated Swagger schema.

// With defaultNullableOnOptionalFields: true
"string?";
// Becomes: { type: "string", nullable: true } (and removed from required list)