2025-05-16

I've released my two personal projects!

I've finally open-sourced and documented the two projects I've been building and using in my many TypeScript projects for the last five or so years. The first one is Trader.ts, a UI library with minimal complexity and a much simpler mental model than React, Angular, Vue, etc. The second one is SQL-Typechecker, a PostgreSQL typechecker and TypeScript type generator.

Trader.ts

The full documentation can be found here, but in short it's the server and UI library I've been using to build classy.school and other commercial projects for quite some time now. It's very, VERY simple. It does no reconciliation, no dirty checking, none of that magic. It's heavily inspired by the frontend library of Ur/Web. As I was writing the docs, I felt almost embarrassed of how simple and archaic it looks on the surface, but I am extremely confident in its quality. The abstractions I've been able to build on top of it (most importantly my Form library, docs incoming) are impossible to do in a sane way in many of the heavy mainstream frameworks. Couldn't be happier!

SQL-Typechecker

The existing TypeScript libraries to interact with PostgreSQL in TypeScript were not good enough. Libraries that come close to what I wanted (but are both not good enough and for other programming languages) are sqlc (Go) and sqlx (Rust).

So I wrote my own: SQL-Typechecker. It's a PostgreSQL parser, typechecker and type generator for TypeScript using PostgreSQL's native support for function definition (CREATE FUNCTION ...). In short, it reads your SQL DDL declarations (CREATE TABLE ...) and SQL function definitions (CREATE FUNCTION ...), runs typechecking and generates TypeScript files to run these functions on your database. It's unique features include:

  • Support for CREATE DOMAIN statements, resulting in branded types. This feature singlehandedly caught more than 20 bugs in my projects in the last year
  • Support for ARRAY_AGG and JSONB_BUILD_OBJECT, allowing you to extract nested relations in a single query (see the extended example here)
  • No special syntax like :variablename, just native PostgreSQL syntax
  • Typechecking of SQL code
  • Better type definitions, especially regarding nullability, than all libraries that rely on PostgreSQL's DESCRIBE feature
  • Custom serialization and deserialization based on type inference, even inside nested structures

Even though not everything that PostgreSQL supports is supported in SQL-Typechecker, I've been able to extend it with every feature, function or piece of syntax that I've needed in my projects over the years.

Why should you care?

If you're happy with TypeScript and JavaScript's current state of libraries, then you probably don't care and that's fine by me. But for me, the TypeScript ecosystem really missed both of these libraries, which are focused on providing full stack type safety, from Database to Browser. I'm a huge TypeScript fan but was jealous of the full stack typechecking of projects like Ur/Web or Ocaml's Ocsigen, so I set out to build the same experience in TypeScript.

Why Typescript if you like Ur/Web, Haskell, and Ocaml so much?

Fair point. It's not for lack of trying! But TypeScript offers a bunch of advantages:

  • TypeScript's tooling is just so much better than any of the above. The typechecker is fast, the editor support is best in class, npm (I use it with nix) is so easy to use (hello Cabal, Dune, etc.).
  • Debugger. Chrome Dev Tools is an incredibly good debugger and works for both Node.js and browser code. The absence of a good debugger in the above languages is basically gamebreaking for me.
  • TypeScript's type system is incredibly strong and easy to use. It comes with some caveats due to its unsoundness and inherits some bad stuff from JavaScript, but eslint catches most of them for me.
  • Close to JavaScript: Like it or not, your code will get compiled to JavaScript if you want to write code for the browser. Closer = easier to debug, think about performance, and more.
  • Not purely functional. This one is probably personal, but for code clarity I still often resort to using statements, loops and mutability on select places in my code. 98% of my code is purely functional (minus monads and effects) and immutable, but that 2% is often gnarly to write in a purely expression-oriented language.

I could honestly go on for hours about this topic, but I'll keep it brief. Get in touch if you want to know more about my software building philosophy!

What now?

Not sure. I've completed my current project and have been focusing the last few weeks on classy.school. The sales part of the business is new to me but exciting. I'll probably still look for another project in the near future, but only time will tell! I've had the honor to lead two very interesting projects in the last few years, so if I can find a project where I get the stakeholder's confidence and believe in the project, I might jump!

Please check out my new open-sources libraries if you're interested and send me some feedback!

Simon