Sync Elm typeswith TypeScript types

Add and change ports and flags with confidence and ease. Elm knows about your types, so why shouldn't TypeScript?

Sign up to receive an Early Access discount code.

We'll never share your email address. Just elm-ts-interop updates and Elm tips. Unsubscribe any time.


Define your interop Definitions

It feels just like using elm/json to build Decoders and Encoders.

module Definitions exposing
( Flags
, flags
, gotUserInfo
, logEvent
import Event exposing (Event)
import Os exposing (Os)
import TsJson.Decode as TsDecode
import TsJson.Encode as TsEncode
type alias Flags =
{ os : Os }
flags : TsDecode.Decoder Flags
flags =
TsDecode.field "os" Os.decoder
|> Flags
logEvent : TsEncode.Encoder Event
logEvent =
gotUserInfo : TsDecode.Decoder { first : String, last : String }
gotUserInfo =
TsDecode.succeed (\first last -> { first = first, last = last })
|> TsDecode.andMap (TsDecode.field "first" TsDecode.string)
|> TsDecode.andMap (TsDecode.field "last" TsDecode.string)

Run the command-line tool

You can run the CLI on your local machine, or on your CI server. It gives you a TypeScript declaration file that lets TypeScript know about the types of the ports and flags you defined.

$ elm-ts-interop-pro
Generated src/Main/index.d.ts

Safely setup ports and flags

Can you spot the errors in this example? Hint: look for the red squiggly line, and hover to read the TypeScript error. Ctrl+space is handy for type-aware auto-complete! Now see if you can fix the error in the interactive editor!

Because we used elm-ts-interop, TypeScript now knows what types are valid for our ports and flags!


Send and Receive typed data from Elm

Use the generated InteropPorts module to easily send and receive type-safe ports and decode your flags.

module Main exposing (main)
import Browser
import Definitions
import Event
import Html exposing (..)
import InteropPorts
import Json.Decode
main : Program Json.Decode.Value Model Msg
main =
{ init = init
, view = view
, update = update
, subscriptions = subscriptions
type alias Model =
Result String Definitions.Flags
init : Json.Decode.Value -> ( Model, Cmd Msg )
init flags =
case InteropPorts.decodeFlags flags of
Err flagsError ->
( Err <| Json.Decode.errorToString flagsError
, Cmd.none
Ok okFlags ->
( Ok okFlags
, InteropPorts.logEvent
{ severity = Event.Info
, message = "Hello!"
type Msg
= GotUser { first : String, last : String }
subscriptions : Model -> Sub Msg
subscriptions _ =
(\toElm ->
case toElm of
InteropPorts.GotUserInfo user ->
GotUser user

Simple one-time price

If you're not satisfied, contact me within the first 14 days and I'll send you a full refund.

Lifetime User License

Improve your Elm workflow with the pro tools.

What's included

  • Pro command-line tool

  • Scaffolding tool to easily generate Encoders and Decoders

Pay once, own it forever