packages feed

aeson-typescript-0.1.0.1: README.md

# Welcome to `aeson-typescript` [![Hackage](https://img.shields.io/hackage/v/aeson-typescript.svg)](https://hackage.haskell.org/package/aeson-typescript) [![Build Status](https://travis-ci.org/codedownio/aeson-typescript.svg)](https://travis-ci.org/codedownio/aeson-typescript)

This library provides a way to generate TypeScript `.d.ts` files that match your existing Aeson `ToJSON` instances.
If you already use Aeson's Template Haskell support to derive your instances, then deriving TypeScript is as simple as

```haskell
$(deriveTypeScript myAesonOptions ''MyType)
```

For example,

```haskell
data D a = Nullary
         | Unary Int
         | Product String Char a
         | Record { testOne   :: Double
                  , testTwo   :: Bool
                  , testThree :: D a
                  } deriving Eq
```

Next we derive the necessary instances.

```haskell
$(deriveTypeScript (defaultOptions {fieldLabelModifier = drop 4, constructorTagModifier = map toLower}) ''D)
```

Now we can use the newly created instances.

```haskell
>>> putStrLn $ formatTSDeclarations $ getTypeScriptDeclaration (Proxy :: Proxy D)

type D<T> = "nullary" | IUnary<T> | IProduct<T> | IRecord<T>;

type IUnary<T> = number;

type IProduct<T> = [string, string, T];

interface IRecord<T> {
  tag: "record";
  One: number;
  Two: boolean;
  Three: D<T>;
}
```

It's important to make sure your JSON and TypeScript are being derived with the same options. For this reason, we
include the convenience `HasJSONOptions` typeclass, which lets you write the options only once, like this:

```haskell
instance HasJSONOptions MyType where getJSONOptions _ = (defaultOptions {fieldLabelModifier = drop 4})

$(deriveJSON (getJSONOptions (Proxy :: Proxy MyType)) ''MyType)
$(deriveTypeScript (getJSONOptions (Proxy :: Proxy MyType)) ''MyType)
```

# Suggestions for use

This library was written to make it easier to typecheck your TypeScript frontend against your Haskell backend. Here's how I like to integrate it into my workflow:

The idea is to set up a separate Haskell executable in your Cabal file whose sole purpose is to generate types. For example, in your hpack `package.yaml` file add a new executable like this:

```yaml
executables:
  ...
  tsdef:
    main: Main.hs
    source-dirs: tsdef
    dependencies:
    - my-main-app
    ...
```

And `tsdef/Main.hs` should look like this:

```haskell
module Main where

import Data.Proxy
import Data.Monoid
import MyLibraries

$(deriveTypeScript (getJSONOptions (Proxy :: Proxy MyType1)) ''MyType1)
$(deriveTypeScript (getJSONOptions (Proxy :: Proxy MyType2)) ''MyType2)
...

main = putStrLn $ formatTSDeclarations (
  (getTypeScriptDeclaration (Proxy :: Proxy MyType1)) <>
  (getTypeScriptDeclaration (Proxy :: Proxy MyType2)) <>
  ...
)
```

Now you can generate the types by running `stack runhaskell tsdef/Main.hs > types.d.ts`. I like to make this an automatic step in my Gulpfile, Webpack config, etc.


# See also

If you want a much more opinionated web framework for generating APIs, check out [servant](http://haskell-servant.readthedocs.io/en/stable/). (Although it doesn't seem to support TypeScript client generation at the moment.)

For another very powerful framework that can generate TypeScript client code based on an API specification, see [Swagger/OpenAPI](https://github.com/swagger-api/swagger-codegen).