A library that uses slonik to generate typescript interfaces based on your sql queries.
The library will make sure that return values from all your SQL queries have strict, accurate TypeScript interfaces.
It provides gradual ramp to type safety, so you don't have to spend any time manually syncing interfaces. Before the types have been generated, results will be typed as a generic dictionary - meaning you can write your queries and business logic as quickly and easily as before, but the compiler will tell you if you got something wrong once you try it out.
This method gives you strong typing, like in an ORM, but avoids the inner-platform effect that tends to come with them. You can rename columns, do any kinds of join you want, and the types generated will be based on the query, not the table, so you won't be limited by ORM feature-sets.
Simple select statements, joins, and updates/inserts using
returning are all supported - any sql query that returns a tabular value will have an interface generated for the row type. The interface will be automatically applied to the appropriate query result.
npm install @slonik/typegennpx slonik-typegen src/generated/db # initialises a placeholder directory for generated types
Setup slonik in with type generation in typescript (e.g. in a
When you first write this code,
getPeople will have return type
But once you run
getPeople() (say, by normal usage of your application, or in an integration test),
@slonik/typegen will inspect the field types of the query result, and generate a typescript interface for it.
Afterwards, without having to modify any code,
getPeople will have return type
Person is defined based on the query. In this case is the schema of the
person table. This allows you to get started fast - just write a query, and you will be able to use the results.
The code generation is opt-in. If you don't provide a path for the generated code to be written, you'll get a normal slonik client with no code generation hooks. It is strongly recommended you don't generate code in production (the example above relies on a simple check of the
NODE_ENV environment variable). When a falsy value is supplied to
sql.Person becomes slonik's
sql template function.
||location to write generated typescript. if this is undefined (or falsy) no types will be written.||
||object produced by the library's codegen. By referencing the export produced in the location set by
||by setting this, you can force any unknown/new queries to be given a particular type. For example, in development, you may want a new query to be typed as
||custom mapper from postgres type name to typescript type as a string, as well as a corresponding function mapping the runtime values - see examples using
||if true, generated code directory will be wiped and reinitialised on startup.||
The tests are a good starting point to see a few different configurations.
How it works
setupTypeGen returns a special
sql proxy object, which allows accessing any string key. When you access a key, it's considered as a query identifier. You'll get a wrapped version of slonik's
sql tagged template variable. When you use it with a tagged template, @slonik/typegen will remember your query and store the identifier against it.
setupTypeGen also returns a slonik interceptor, defining a hook to be run after every query is executed. The hook looks up the query identifier from the query taht was run, and generates a typescript interface from the field metadata provided by postgres. The interface is written to disk, and added to the
KnownTypes definition. The typescript compiler will then automatically gain type information corresponding to that query.
- You can re-use the same type name for many queries. But you should only do this if the types represented by any single name are the same, since the resultant type will be a union of all of the outputs (meaning
A | B- i.e. only fields common to both will be accessible).
- Check in the types to source control. They're generated code, but it makes it much easier to track what was happened when a query was update, and see those changes over time.
- After running CI, it's worth making sure that there are no working copy changes. For git, you can use check-clean:
yarn test:integrationnpx check-clean