Overview
The Make utility provides helper methods for creating type-safe schema values.
It ensures proper type inference and validation for constants, unions, and other special values.
๐ก Pro Tip: Use Make for values that need strict type safety and
Mod for transforming existing schemas.
Make.const()
MethodCreate a constant value that must match exactly. Safer than using raw values because it provides better type inference and validation.
Signature
static const<const T extends string | number | boolean>(
value: T
): ConstantValue & { const: T }
Basic Usage
import { Interface, Make } from "fortify-schema";
const ConfigSchema = Interface({
// String constants
apiVersion: Make.const("v2.1"),
environment: Make.const("production"),
// Numeric constants
maxRetries: Make.const(3),
timeout: Make.const(5000),
// Boolean constants
enableLogging: Make.const(true),
debugMode: Make.const(false)
});
// Valid data
ConfigSchema.parse({
apiVersion: "v2.1", // โ
Matches exactly
environment: "production", // โ
Matches exactly
maxRetries: 3, // โ
Matches exactly
timeout: 5000, // โ
Matches exactly
enableLogging: true, // โ
Matches exactly
debugMode: false // โ
Matches exactly
});
// Invalid data
ConfigSchema.parse({
apiVersion: "v2.0", // โ Must be "v2.1"
environment: "staging", // โ Must be "production"
maxRetries: 5, // โ Must be 3
timeout: 3000, // โ Must be 5000
enableLogging: false, // โ Must be true
debugMode: true // โ Must be false
});
Use Cases
๐ API Versioning
Enforce specific API versions in requests
โ๏ธ Configuration
Lock down critical config values
๐ฏ Feature Flags
Validate feature flag states
๐ Protocol Compliance
Ensure protocol-specific values
Advanced Example
// Complex configuration with constants
const DatabaseConfigSchema = Interface({
driver: Make.const("postgresql"),
version: Make.const("14.5"),
ssl: Make.const(true),
poolSize: Make.const(20),
// Mix with other types
host: "string",
port: "number",
database: "string",
username: "string",
password: "string"
});
// Type inference works perfectly
type DatabaseConfig = InferType<typeof DatabaseConfigSchema>;
// {
// driver: "postgresql"; // Literal type
// version: "14.5"; // Literal type
// ssl: true; // Literal type
// poolSize: 20; // Literal type
// host: string;
// port: number;
// database: string;
// username: string;
// password: string;
// }
Make.union()
MethodCreate a union type with multiple allowed values. Provides proper type inference for all possible values.
Signature
static union<const T extends readonly string[]>(
...values: T
): UnionValue<T>
Basic Usage
import { Interface, Make } from "fortify-schema";
const UserSchema = Interface({
// Status with 3 possible values
status: Make.union("pending", "accepted", "rejected"),
// Priority levels
priority: Make.union("low", "medium", "high", "critical"),
// User roles
role: Make.union("admin", "moderator", "user", "guest")
});
// Valid data
UserSchema.parse({
status: "pending", // โ
One of the allowed values
priority: "high", // โ
One of the allowed values
role: "admin" // โ
One of the allowed values
});
// Invalid data
UserSchema.parse({
status: "approved", // โ Not in union
priority: "urgent", // โ Not in union
role: "superadmin" // โ Not in union
});
Type Inference
const StatusSchema = Interface({
status: Make.union("pending", "accepted", "rejected")
});
type Status = InferType<typeof StatusSchema>;
// { status: "pending" | "accepted" | "rejected" }
// TypeScript autocomplete works perfectly
const handleStatus = (data: Status) => {
if (data.status === "pending") {
// Handle pending
} else if (data.status === "accepted") {
// Handle accepted
} else if (data.status === "rejected") {
// Handle rejected
}
// TypeScript knows all possible values!
};
Real-World Example
// E-commerce order schema
const OrderSchema = Interface({
orderId: "uuid",
// Order status workflow
status: Make.union(
"cart",
"pending_payment",
"payment_failed",
"paid",
"processing",
"shipped",
"delivered",
"cancelled",
"refunded"
),
// Payment method
paymentMethod: Make.union(
"credit_card",
"debit_card",
"paypal",
"stripe",
"bank_transfer"
),
// Shipping method
shippingMethod: Make.union(
"standard",
"express",
"overnight",
"pickup"
),
items: "array",
total: "number",
createdAt: "date"
});
Make.unionOptional()
MethodCreate an optional union type. The field can be one of the specified values or undefined.
Signature
static unionOptional<const T extends readonly string[]>(
...values: T
): UnionValue<T> & { optional: true }
Basic Usage
import { Interface, Make } from "fortify-schema";
const ProductSchema = Interface({
id: "uuid",
name: "string",
// Optional shipping type
shippingType: Make.unionOptional("standard", "express", "overnight"),
// Optional gift wrapping
giftWrap: Make.unionOptional("basic", "premium", "deluxe")
});
// All valid
ProductSchema.parse({
id: "123",
name: "Product",
shippingType: "express" // โ
Specified
});
ProductSchema.parse({
id: "123",
name: "Product"
// โ
shippingType and giftWrap omitted
});
ProductSchema.parse({
id: "123",
name: "Product",
shippingType: "standard",
giftWrap: "premium"
// โ
Both specified
});
Type Inference
const Schema = Interface({
type: Make.unionOptional("standard", "express", "overnight")
});
type Inferred = InferType<typeof Schema>;
// { type?: "standard" | "express" | "overnight" | undefined }
// TypeScript handles optional correctly
const process = (data: Inferred) => {
if (data.type) {
// data.type is "standard" | "express" | "overnight"
console.log(`Shipping type: ${data.type}`);
} else {
console.log("No shipping type specified");
}
};
Method Comparison
| Method | Purpose | Required | Example |
|---|---|---|---|
Make.const() |
Single exact value | Yes | Make.const("v1.0") |
Make.union() |
Multiple allowed values | Yes | Make.union("a", "b", "c") |
Make.unionOptional() |
Optional multiple values | No | Make.unionOptional("x", "y") |
โจ Best Practices
1. Use Make.const() for Fixed Values
When a value must never change (API versions, protocol identifiers), use Make.const().
2. Prefer Make.union() Over String Literals
Use Make.union() instead of "a|b|c" for better type inference and IDE support.
3. Keep Union Values Descriptive
Use clear, descriptive values: "pending_payment" instead of "pp".
4. Document Complex Unions
Add comments explaining what each union value represents in your business logic.