Home Announcing Aeson-TypeScript
Post
Cancel

Announcing Aeson-TypeScript

Haskell already has world-class support for converting data to and from JSON using the Aeson library. But what if you want to ensure that your TypeScript frontend is using your data types correctly?

If you already use Aeson’s autogenerated Template Haskell instances, then this library will let you generate TypeScript definitions that match up with them perfectly.

See the Github readme or the Hackage docs for more details, including some suggestions on how you can generate type files automatically as part of your frontend build process.

The library is on Stackage as of LTS-10.8.

Notes

This was my first significant Template Haskell project. Here are some notes on the implementation:

  • The key typeclass is called TypeScript a and the key functions within it are getTypeScriptDeclarations :: Proxy a -> [TSDeclaration] and getTypeScriptType :: Proxy a -> String. It turns out Data.Proxy is a great way to write functions that depend only on the type of something, rather than on a concrete value. As an extra bonus, Data.Proxy is poly-kinded, so you can naturally use higher-kinded types with it. I initially wrote the library using Data.Tagged but it wasn’t poly-kinded (EDIT: it is actually poly-kinded, but I couldn’t figure it out at the time) and was also slightly more verbose.

  • Writing Template Haskell that works across all the different GHC versions can be painful. I found the th-abstraction library to be an essential resource for reifying types. Nonetheless, I wasn’t able to avoid a few #if macros to deal with slight changes in the template-haskell library over time.

  • The way this library is tested is cool: with the exception of a few hand-coded spot checks, the tests just emit TypeScript definitions and values into a .ts file and then run the TypeScript compiler on it to make sure the compiler is happy with it.

  • The hardest part of making this library match Aeson was all the different combinations of encoding options that Aeson supports. Aeson has 4 different “sum encoding” strategies for how to encode a value constructor, plus several additional boolean flags like tagSingleConstructors, unwrapUnaryRecords, etc. There’s a slight TODO here; see this issue.

This post is licensed under CC BY 4.0 by the author.