Skip to main content

Type mapping

How pg-describe-gen turns a PostgreSQL type name into a TypeScript type.

PostgreSQLTypeScript
smallint, integer, real, double precisionnumber
bigintstringan int8 does not fit in a JS number; node-postgres returns a string
numeric, decimalstringarbitrary precision, and floats are wrong for money
booleanboolean
text, varchar, char, uuid, citext, inet, intervalstring
date, timestamp, timestamptzDate
time, time with time zonestringno Date equivalent
byteaBuffer
json, jsonbunknownnarrow it yourself
T[]T[]any dimension
anything elseunknownwith a warning

The mapping targets what node-postgres actually returns at run time, not what the SQL type resembles. bigint and numeric arriving as strings is the case that surprises people, and typing them number would be a lie the compiler would then help you build on.

Overriding

Enums, domains and user-defined types fall through to unknown with a warning. Map them, or override any built-in, with a types block in the config:

{
"queries": "queries",
"output": "src/generated/queries.ts",
"types": {
"order_status": "'pending' | 'shipped' | 'cancelled'",
"bigint": "bigint",
"jsonb": "Record<string, unknown>"
}
}

Keys are PostgreSQL type names as pg_describe reports them in type_name; the quickest way to get the exact spelling is to run the query and look:

SELECT DISTINCT type_name FROM pg_describe($$SELECT * FROM orders$$);

Values are emitted verbatim into the generated file, so any TypeScript type expression works — a union, an imported type name, a branded type. Nothing validates it beyond tsc on the generated output.

If you map bigint to the JS bigint, remember to configure node-postgres to parse int8 accordingly; the generator describes types, it does not install parsers.