Copyright | (c) 2018 Tom McLaughlin |
---|---|
License | BSD3 |
Stability | experimental |
Portability | portable |
Safe Haskell | None |
Language | Haskell2010 |
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
$(deriveTypeScript
myAesonOptions ''MyType)
For example,
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.
$(deriveTypeScript
(defaultOptions
{fieldLabelModifier
=drop
4,constructorTagModifier
= map toLower}) ''D)
Now we can use the newly created instances.
>>> putStrLn $formatTSDeclarations
$getTypeScriptDeclarations
(Proxy :: Proxy D) type D<T> = INullary<T> | IUnary<T> | IProduct<T> | IRecord<T>; interface INullary<T> { tag: "nullary"; } interface IUnary<T> { tag: "unary"; contents: number; } interface IProduct<T> { tag: "product"; contents: [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:
instance HasJSONOptions MyType where getJSONOptions _ = (defaultOptions
{fieldLabelModifier
=drop
4}) $(deriveJSON
(getJSONOptions
(Proxy :: Proxy MyType)) ''MyType) $(deriveTypeScript
(getJSONOptions
(Proxy :: Proxy MyType)) ''MyType)
Or, if you want to be even more concise and don't mind defining the instances in the same file,
myOptions =defaultOptions
{fieldLabelModifier
=drop
4} $(deriveJSONAndTypeScript
myOptions ''MyType)
Remembering that the Template Haskell Q
monad is an ordinary monad, you can derive instances for several types at once like this:
$(mconcat
<$>traverse
(deriveJSONAndTypeScript
myOptions) [''MyType1, ''MyType2, ''MyType3])
Once you've defined all necessary instances, you can write a main function to dump them out into a .d.ts
file. For example:
main = putStrLn $formatTSDeclarations
( (getTypeScriptDeclarations
(Proxy :: Proxy MyType1)) <> (getTypeScriptDeclarations
(Proxy :: Proxy MyType2)) <> ... )
Synopsis
- deriveTypeScript :: Options -> Name -> Q [Dec]
- class TypeScript a where
- getTypeScriptDeclarations :: Proxy a -> [TSDeclaration]
- getTypeScriptType :: Proxy a -> String
- getTypeScriptOptional :: Proxy a -> Bool
- data TSDeclaration
- formatTSDeclarations :: [TSDeclaration] -> String
- formatTSDeclarations' :: FormattingOptions -> [TSDeclaration] -> String
- formatTSDeclaration :: FormattingOptions -> TSDeclaration -> String
- data FormattingOptions = FormattingOptions {
- numIndentSpaces :: Int
- interfaceNameModifier :: String -> String
- typeNameModifier :: String -> String
- class HasJSONOptions a where
- getJSONOptions :: Proxy a -> Options
- deriveJSONAndTypeScript :: Options -> Name -> Q [Dec]
Documentation
:: Options | Encoding options. |
-> Name | Name of the type for which to generate a |
-> Q [Dec] |
Generates a TypeScript
instance declaration for the given data type.
The main typeclass
class TypeScript a where Source #
The typeclass that defines how a type is turned into TypeScript.
The getTypeScriptDeclarations
method describes the top-level declarations that are needed for a type,
while getTypeScriptType
describes how references to the type should be translated. The getTypeScriptOptional
method exists purely so that Maybe
types can be encoded with a question mark.
Instances for common types are built-in and are usually very simple; for example,
instance TypeScript Bool where getTypeScriptType _ = "boolean"
Most of the time you should not need to write instances by hand; in fact, the TSDeclaration
constructors are deliberately opaque. However, you may occasionally need to specify the type of something.
For example, since UTCTime
is encoded to a JSON string and is not built-in to this library:
import Data.Time.Clock (UTCTime) instance TypeScript UTCTime where getTypeScriptType _ = "string"
If you need to write a definition for a higher-order type, it may depend on a type parameter. For example,
a Set
is encoded to a JSON list of the underlying type:
instance (TypeScript a) => TypeScript (Set a) where getTypeScriptType _ = getTypeScriptType (Proxy :: Proxy a) <> "[]";
getTypeScriptDeclarations :: Proxy a -> [TSDeclaration] Source #
Get the declaration(s) needed for this type.
getTypeScriptType :: Proxy a -> String Source #
Get the type as a string.
getTypeScriptOptional :: Proxy a -> Bool Source #
Get a flag representing whether this type is optional.
Instances
data TSDeclaration Source #
Instances
Eq TSDeclaration Source # | |
Defined in Data.Aeson.TypeScript.Types (==) :: TSDeclaration -> TSDeclaration -> Bool # (/=) :: TSDeclaration -> TSDeclaration -> Bool # | |
Show TSDeclaration Source # | |
Defined in Data.Aeson.TypeScript.Types showsPrec :: Int -> TSDeclaration -> ShowS # show :: TSDeclaration -> String # showList :: [TSDeclaration] -> ShowS # |
Formatting declarations
formatTSDeclarations :: [TSDeclaration] -> String Source #
Same as formatTSDeclarations'
, but uses default formatting options.
formatTSDeclarations' :: FormattingOptions -> [TSDeclaration] -> String Source #
Format a list of TypeScript declarations into a string, suitable for putting directly into a .d.ts
file.
formatTSDeclaration :: FormattingOptions -> TSDeclaration -> String Source #
Format a single TypeScript declaration. This version accepts a FormattingOptions object in case you want more control over the output.
data FormattingOptions Source #
FormattingOptions | |
|
Convenience tools
class HasJSONOptions a where Source #
Convenience typeclass class you can use to "attach" a set of Aeson encoding options to a type.
getJSONOptions :: Proxy a -> Options Source #
deriveJSONAndTypeScript Source #
:: Options | Encoding options. |
-> Name | Name of the type for which to generate |
-> Q [Dec] |
Convenience function to generate ToJSON
, FromJSON
, and TypeScript
instances simultaneously, so the instances are guaranteed to be in sync.
This function is given mainly as an illustration. If you want some other permutation of instances, such as ToJSON
and TypeScript
only, just take a look at the source and write your own version.
Since: 0.1.0.4