Json Schema Type Builder with Static Type Resolution for TypeScript
—
High-performance validation through schema compilation to optimized JavaScript code. The TypeCompiler generates fast validation functions that significantly outperform standard JSON Schema validators.
Compiles a schema to an optimized runtime checker.
/**
* Compiles schema to optimized runtime checker
* @param schema - Schema to compile
* @returns TypeCheck instance with validation methods
*/
function Compile<T extends TSchema>(schema: T, references?: TSchema[]): TypeCheck<T>;
interface TypeCheck<T extends TSchema> {
/** Check if value matches schema */
Check(value: unknown): value is Static<T>;
/** Get validation errors for value */
Errors(value: unknown): ValueErrorIterator;
/** Get source code of compiled checker */
Code(): string;
/** Decode transformed values (for transform schemas) */
Decode(value: unknown): StaticDecode<T>;
/** Encode values for transformation (for transform schemas) */
Encode(value: unknown): StaticEncode<T>;
}Usage Examples:
import { TypeCompiler, Type } from "@sinclair/typebox";
const User = Type.Object({
name: Type.String({ minLength: 2 }),
age: Type.Number({ minimum: 0, maximum: 120 }),
email: Type.String({ format: 'email' }),
isActive: Type.Optional(Type.Boolean())
});
// Compile the schema
const userChecker = TypeCompiler.Compile(User);
// Use compiled checker for validation
const userData = { name: "Alice", age: 25, email: "alice@example.com" };
if (userChecker.Check(userData)) {
console.log("Valid user:", userData);
// TypeScript knows userData is properly typed here
} else {
console.log("Invalid user");
for (const error of userChecker.Errors(userData)) {
console.log(`${error.path}: ${error.message}`);
}
}Generates validation code as a string for inspection or advanced use cases.
/**
* Generates validation code as string
* @param schema - Schema to generate code for
* @param options - Code generation options
* @returns Generated JavaScript code
*/
function Code<T extends TSchema>(schema: T, references?: TSchema[], options?: TypeCompilerCodegenOptions): string;
interface TypeCompilerCodegenOptions {
/** Function name for generated code (default: 'check') */
functionName?: string;
/** Include source maps in generated code */
sourceMaps?: boolean;
/** Optimize for size vs speed */
optimize?: 'size' | 'speed';
}Usage Examples:
const User = Type.Object({
name: Type.String(),
age: Type.Number()
});
// Generate code with default options
const defaultCode = TypeCompiler.Code(User);
console.log(defaultCode);
// Generate code with custom function name
const namedCode = TypeCompiler.Code(User, {
functionName: 'validateUser'
});
// Generated code can be used in dynamic contexts
const validateFn = new Function('return ' + namedCode)();
const isValid = validateFn({ name: "Alice", age: 25 });The compiled validators provide significant performance benefits:
Performance Example:
import { TypeCompiler, Value, Type } from "@sinclair/typebox";
const schema = Type.Object({
users: Type.Array(Type.Object({
id: Type.String(),
name: Type.String(),
email: Type.String({ format: 'email' }),
age: Type.Number({ minimum: 0, maximum: 120 })
}))
});
const compiledChecker = TypeCompiler.Compile(schema);
const largeDataset = /* ... thousands of user objects ... */;
// Compiled validation (fast)
console.time('Compiled');
for (const item of largeDataset) {
compiledChecker.Check(item);
}
console.timeEnd('Compiled');
// Standard validation (slower)
console.time('Standard');
for (const item of largeDataset) {
Value.Check(schema, item);
}
console.timeEnd('Standard');Compiled checkers provide detailed error information with path and context.
interface ValueErrorIterator {
[Symbol.iterator](): IterableIterator<ValueError>;
First(): ValueError | undefined;
}
interface ValueError {
type: ValueErrorType;
schema: TSchema;
path: string;
value: unknown;
message: string;
}Usage Examples:
const schema = Type.Object({
nested: Type.Object({
items: Type.Array(Type.Number({ minimum: 0 }))
})
});
const checker = TypeCompiler.Compile(schema);
const invalidData = { nested: { items: [1, -2, 3] } };
if (!checker.Check(invalidData)) {
for (const error of checker.Errors(invalidData)) {
console.log(`Path: ${error.path}`);
console.log(`Message: ${error.message}`);
console.log(`Value: ${JSON.stringify(error.value)}`);
}
// Output:
// Path: /nested/items/1
// Message: Expected number to be greater or equal to 0
// Value: -2
}Examine the generated validation code for debugging or optimization.
const User = Type.Object({
name: Type.String({ minLength: 1 }),
age: Type.Number({ minimum: 0 })
});
const checker = TypeCompiler.Compile(User);
console.log(checker.Code());
// Generated code example:
// function check(value) {
// return (
// typeof value === 'object' && value !== null &&
// typeof value.name === 'string' && value.name.length >= 1 &&
// typeof value.age === 'number' && value.age >= 0
// );
// }While TypeCompiler supports most TypeBox schemas, some advanced features have limitations:
Fallback Strategy:
const TransformSchema = Type.Transform(Type.String())
.Decode(value => new Date(value))
.Encode(value => value.toISOString());
// Compilation not supported for transforms
try {
const checker = TypeCompiler.Compile(TransformSchema);
} catch (error) {
console.log("Compilation failed, using Value.Check");
// Fallback to runtime validation
const isValid = Value.Check(TransformSchema, someValue);
}Compile schemas once at startup for optimal performance.
// Schema definitions
const schemas = {
User: Type.Object({
name: Type.String(),
email: Type.String({ format: 'email' })
}),
Product: Type.Object({
id: Type.String(),
price: Type.Number({ minimum: 0 })
})
};
// Pre-compile all schemas
const checkers = {
User: TypeCompiler.Compile(schemas.User),
Product: TypeCompiler.Compile(schemas.Product)
};
// Use compiled checkers in request handlers
function validateUser(userData: unknown) {
return checkers.User.Check(userData);
}function validateWithErrors<T extends TSchema>(
checker: TypeCheck<T>,
value: unknown
): { valid: boolean; errors: ValueError[] } {
if (checker.Check(value)) {
return { valid: true, errors: [] };
}
const errors = Array.from(checker.Errors(value));
return { valid: false, errors };
}
// Usage
const result = validateWithErrors(userChecker, userData);
if (!result.valid) {
console.log("Validation errors:", result.errors.map(e => e.message));
}// Express.js middleware example
function validateBody<T extends TSchema>(checker: TypeCheck<T>) {
return (req: Request, res: Response, next: NextFunction) => {
if (checker.Check(req.body)) {
next();
} else {
const errors = Array.from(checker.Errors(req.body));
res.status(400).json({
error: "Validation failed",
details: errors.map(e => ({ path: e.path, message: e.message }))
});
}
};
}
// Usage
app.post('/users', validateBody(userChecker), (req, res) => {
// req.body is guaranteed to be valid User type
const user = req.body as Static<typeof User>;
// ... handle request
});interface TypeCheck<T extends TSchema> {
/** Check if value matches the compiled schema */
Check(value: unknown): value is Static<T>;
/** Get iterator of validation errors */
Errors(value: unknown): ValueErrorIterator;
/** Get the generated validation code */
Code(): string;
}
interface TypeCompilerCodegenOptions {
/** Name for the generated validation function */
functionName?: string;
/** Include source mapping information */
sourceMaps?: boolean;
/** Optimization strategy */
optimize?: 'size' | 'speed';
}
// Re-exported from errors module
interface ValueError {
type: ValueErrorType;
schema: TSchema;
path: string;
value: unknown;
message: string;
}
interface ValueErrorIterator extends IterableIterator<ValueError> {
/** Get the first error without iteration */
First(): ValueError | undefined;
}Install with Tessl CLI
npx tessl i tessl/npm-sinclair--typebox