Published October 18, 2021

elm-ts-interop init Command, Codec and Pipeline APIs, and docs site

This week I have some improvements to announce for elm-ts-interop. In particular, I've been focused on making it easier to get started with the free Community Edition. And I've also shipped some new APIs for building up your type-safe Encoders and Decoders.

If you're not familiar with elm-ts-interop, it's a tool that generates TypeScript types from your custom JSON Decoders and Encoders to ensure that the types are in sync between your Elm app and TypeScript code. If you're not using TypeScript in your project, you can even benefit from the improved type-safety using vanilla JavaScript by using JSDoc comments ([TypeScript Without Transpilation]).

You can learn more about how elm-ts-interop works and find some learning resources.

Starter Repo with ViteJS and TypeScript#

There is now a starter setup for the elm-ts-interop Community Edition. It uses a simple ViteJS config to load in Elm and TypeScript code, and it also has an eslint rule to enforce exhaustive switch statements so you can add a new FromElm port (Cmd port) and get a type error reminding you to handle that new data in TypeScript. It feels just like adding a new Msg variant and handling it in your Elm update function.

The starter repo is at And if you're a pro user, you can see the example Pro setup on the pro branch.

elm-ts-interop Community Edition Setup Guide#

You can find the newly published docs which inclue a thorough walkthrough for how to get started with elm-ts-interop. To make it easier to get set up, I've also added an elm-ts-interop init command that will scaffold the two Elm files you need to get started. Try it out and let me know how it goes!

elm-ts-interop Watch Mode#

You can run elm-ts-interop with a --watch flag to have it re-run any time your Elm code changes. That helps speed up the feedback loop and get compiler errors as you change your InteropDefinitions module.

Codec and Pipeline APIs#

The elm-ts-json Elm package is the secret sauce for getting type information from your Decoders and Encoders. The core API remains the same, but version 2.0 of the package now comes with a Codec API (thank you miniBill for the great API design!) as well as a port of the NoRedInk/elm-json-decode-pipeline API. The Codec API also includes a new addition from miniBill's Codec API for customizing the names of fields (rather than having custom types encoded as an Array of positional values). Check out the new TsJson.Codec API and TsJson.Pipeline API.

Simplified Discriminated Union Decoder#

If your using the convention of having a string field that is used to determine the type of decoding to use (Discriminated Unions), there's now a helper that makes it a lot easier to do that with elm-ts-json.

import TsJson.Decode as TsDecode

type User
    = Admin { id : Int }
    | Guest

TsDecode.discriminatedUnion "role"
    [ ( "admin"
        , TsDecode.succeed (\id -> Admin { id = id })
        |> TsDecode.andMap (TsDecode.field "id"
    , ( "guest", TsDecode.succeed Guest )
    |> TsDecode.runExample """{"role": "admin", "id": 123}"""
--> { decoded = Ok (Admin { id = 123 })
--> , tsType = """{ id : number; role : "admin" } | { role : "guest" }"""
--> }

As always, feel free to ask me questions on Twitter @dillontkearns, or on Slack (we have an #elm-ts-interop channel). Happy type-safe coding!