Type System Mappings
Purpose: PostgreSQL ↔ TypeScript/Zod type conversions
Last Updated: 2024-11-28
Overview
The codegen system maps PostgreSQL types to TypeScript types with Zod validation. This document describes how each PostgreSQL type category translates to TypeScript.
Base Type Mappings
| PostgreSQL | TypeScript | Zod Schema |
|---|---|---|
integer, int4 |
number |
z.number().int() |
bigint, int8 |
bigint |
z.bigint() |
smallint, int2 |
number |
z.number().int() |
numeric, decimal |
number |
z.number() |
real, float4 |
number |
z.number() |
double precision, float8 |
number |
z.number() |
text |
string |
z.string() |
varchar(n) |
string |
z.string() |
char(n) |
string |
z.string() |
boolean |
boolean |
z.boolean() |
timestamp |
Date |
z.string().datetime() |
timestamptz |
Date |
z.string().datetime() |
date |
Date |
z.string().date() |
time |
string |
z.string().time() |
interval |
string |
z.string() |
json |
unknown |
z.unknown() |
jsonb |
unknown |
z.unknown() |
uuid |
string |
z.string().uuid() |
bytea |
Buffer |
z.instanceof(Buffer) |
ltree |
string |
z.string() |
Composite Types (Records)
PostgreSQL Definition
CREATE TYPE graph.node_data AS (
id bigint,
type_namespace ltree,
data jsonb,
created_at timestamp
);
Generated TypeScript
export const nodeDataSchema = z.object({
id: z.bigint(),
type_namespace: z.string(),
data: z.unknown(),
created_at: z.string().datetime()
});
export type NodeData = z.infer<typeof nodeDataSchema>;
Enum Types
PostgreSQL Definition
CREATE TYPE auth.algorithm AS ENUM (
'RS256',
'RS384',
'RS512',
'ES256',
'ES384'
);
Generated TypeScript
export const algorithmSchema = z.enum([
'RS256',
'RS384',
'RS512',
'ES256',
'ES384'
]);
export type Algorithm = z.infer<typeof algorithmSchema>;
// Type: 'RS256' | 'RS384' | 'RS512' | 'ES256' | 'ES384'
Array Types
PostgreSQL Definition
CREATE FUNCTION get_user_tags(p_user_id bigint)
RETURNS text[]
Generated TypeScript
export async function getUserTags(
client: PoolClient,
params: { p_user_id: bigint }
): Promise<string[]>
Nested Arrays
PostgreSQL: integer[][]
TypeScript: number[][]
Zod: z.array(z.array(z.number().int()))
Domain Types
Domains are constrained base types.
PostgreSQL Definition
CREATE DOMAIN email AS text
CHECK (VALUE ~ '^[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,}$');
Generated TypeScript
export const emailSchema = z.string().refine(
(val) => /^[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,}$/.test(val),
{ message: 'Invalid email format' }
);
export type Email = z.infer<typeof emailSchema>;
Common Domain Patterns
Numeric bounds:
CREATE DOMAIN positive_int AS integer CHECK (VALUE > 0);
→ z.number().int().min(1)
String length:
CREATE DOMAIN username AS varchar(50) CHECK (LENGTH(VALUE) >= 3);
→ z.string().min(3).max(50)
Range Types
PostgreSQL Definition
CREATE FUNCTION get_date_range()
RETURNS daterange;
Generated TypeScript
export const dateRangeSchema = z.object({
lower: z.string().date(),
upper: z.string().date(),
lowerInclusive: z.boolean(),
upperInclusive: z.boolean()
});
export type DateRange = z.infer<typeof dateRangeSchema>;
Range Type Mappings
| PostgreSQL | Lower/Upper Type |
|---|---|
int4range |
number |
int8range |
bigint |
numrange |
number |
tsrange |
Date |
tstzrange |
Date |
daterange |
Date |
Nullable Types
PostgreSQL Definition
CREATE FUNCTION find_user(p_email text)
RETURNS bigint -- can return NULL
Generated TypeScript
export async function findUser(
client: PoolClient,
params: { p_email: string }
): Promise<bigint | null>
Optional Parameters
PostgreSQL Definition
CREATE FUNCTION create_user(
p_email text,
p_name text DEFAULT NULL,
p_age integer DEFAULT 18
)
RETURNS bigint
Generated TypeScript
export async function createUser(
client: PoolClient,
params: {
p_email: string;
p_name?: string | null; // Optional and nullable
p_age?: number; // Optional with default
}
): Promise<bigint>
Table Return Types
PostgreSQL Definition
CREATE FUNCTION list_users()
RETURNS TABLE (
id bigint,
email text,
created_at timestamp
)
Generated TypeScript
export type ListUsersRow = {
id: bigint;
email: string;
created_at: Date;
};
export async function listUsers(
client: PoolClient
): Promise<ListUsersRow[]>
SETOF Return Types
Similar to TABLE return types - both return arrays.
PostgreSQL Definition
CREATE FUNCTION get_active_users()
RETURNS SETOF auth.user_record
Generated TypeScript
export async function getActiveUsers(
client: PoolClient
): Promise<UserRecord[]>
Void Return Type
PostgreSQL Definition
CREATE FUNCTION log_action(p_message text)
RETURNS void
Generated TypeScript
export async function logAction(
client: PoolClient,
params: { p_message: string }
): Promise<void>
Type Safety Guarantees
Compile-Time Safety
// ✅ Valid - all types match
await createUser(client, {
p_email: 'user@example.com',
p_age: 25
});
// ❌ Compile error - wrong type
await createUser(client, {
p_email: 'user@example.com',
p_age: '25' // string instead of number
});
// ❌ Compile error - missing required parameter
await createUser(client, {
p_age: 25 // missing p_email
});
Runtime Validation
try {
await createUser(client, {
p_email: untrustedInput,
p_age: userAge
});
} catch (error) {
if (error instanceof ZodError) {
console.error('Validation failed:', error.errors);
}
}
Special Cases
Overloaded Functions
PostgreSQL:
CREATE FUNCTION process_data(p_id bigint) RETURNS text;
CREATE FUNCTION process_data(p_id bigint, p_flag boolean) RETURNS text;
Generated TypeScript (first signature only):
export async function processData(
client: PoolClient,
params: { p_id: bigint }
): Promise<string>
Workaround: Create wrapper functions with different names.
Custom Types
Unsupported PostgreSQL types (geometric, network):
- Map to
unknownorstring - Add custom validation if needed
- Document expected format
Type Inference
Using z.infer
const userSchema = z.object({
id: z.bigint(),
email: z.string(),
age: z.number().int()
});
// Infer TypeScript type from schema
type User = z.infer<typeof userSchema>;
// Equivalent to:
// type User = {
// id: bigint;
// email: string;
// age: number;
// }
Examples
For detailed code examples, see:
- Schema Examples - Type mapping examples with code
- Function Patterns - Function signature examples
Related Documentation
- Overview - System architecture
- Schema Generation - Builder details
- Function Wrappers - Using generated functions
- Schema Builders - Builder implementations
Key Takeaway: Every PostgreSQL type maps to a TypeScript type with Zod validation, ensuring both compile-time and runtime safety.