diff --git a/CHANGELOG.md b/CHANGELOG.md
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,5 +1,17 @@
 # Change log
 
+
+## (unreleased)
+
+## 0.5.0.0
+
+* [#35](https://github.com/codedownio/aeson-typescript/pull/35)
+    * Add `Data.Aeson.TypeScript.LegalName` module for checking whether a name is a legal JavaScript name or not.
+    * The `defaultFormatter` will `error` if the name contains illegal characters.
+* Be able to transfer Haddock comments to emitted TypeScript (requires GHC >= 9.2 and `-haddock` flag)
+* Add support for @no-emit-typescript in Haddocks for constructors and record fields (requires GHC >= 9.2 and `-haddock` flag)
+* Support GHC 9.6.1
+
 ## 0.4.2.0
 
 * Fix TypeScript (A.KeyMap a) instance
diff --git a/README.md b/README.md
--- a/README.md
+++ b/README.md
@@ -16,6 +16,7 @@
          | Product String Char a
          | Record { testOne   :: Double
                   , testTwo   :: Bool
+                  -- | This docstring will go into the generated TypeScript!
                   , testThree :: D a
                   } deriving Eq
 ```
@@ -41,6 +42,7 @@
   tag: "record";
   One: number;
   Two: boolean;
+  // This docstring will go into the generated TypeScript!
   Three: D<T>;
 }
 ```
diff --git a/aeson-typescript.cabal b/aeson-typescript.cabal
--- a/aeson-typescript.cabal
+++ b/aeson-typescript.cabal
@@ -1,11 +1,11 @@
 cabal-version: 1.12
 
--- This file has been generated from package.yaml by hpack version 0.35.0.
+-- This file has been generated from package.yaml by hpack version 0.35.1.
 --
 -- see: https://github.com/sol/hpack
 
 name:           aeson-typescript
-version:        0.4.2.0
+version:        0.5.0.0
 synopsis:       Generate TypeScript definition files from your ADTs
 description:    Please see the README on Github at <https://github.com/codedownio/aeson-typescript#readme>
 category:       Text, Web, JSON
@@ -36,6 +36,7 @@
       Data.Aeson.TypeScript.TH
       Data.Aeson.TypeScript.Internal
       Data.Aeson.TypeScript.Recursive
+      Data.Aeson.TypeScript.LegalName
   other-modules:
       Data.Aeson.TypeScript.Formatting
       Data.Aeson.TypeScript.Instances
@@ -47,6 +48,16 @@
       Paths_aeson_typescript
   hs-source-dirs:
       src
+  default-extensions:
+      LambdaCase
+      MultiWayIf
+      NamedFieldPuns
+      OverloadedStrings
+      QuasiQuotes
+      RecordWildCards
+      ScopedTypeVariables
+      TupleSections
+      ViewPatterns
   build-depends:
       aeson
     , base >=4.7 && <5
@@ -68,7 +79,9 @@
       ClosedTypeFamilies
       Formatting
       Generic
+      GetDoc
       HigherKind
+      LegalNameSpec
       NoOmitNothingFields
       ObjectWithSingleFieldNoTagSingleConstructors
       ObjectWithSingleFieldTagSingleConstructors
@@ -87,6 +100,7 @@
       Data.Aeson.TypeScript.Formatting
       Data.Aeson.TypeScript.Instances
       Data.Aeson.TypeScript.Internal
+      Data.Aeson.TypeScript.LegalName
       Data.Aeson.TypeScript.Lookup
       Data.Aeson.TypeScript.Recursive
       Data.Aeson.TypeScript.TH
@@ -98,7 +112,21 @@
   hs-source-dirs:
       test
       src
-  ghc-options: -Wall -threaded -rtsopts -with-rtsopts=-N
+  default-extensions:
+      LambdaCase
+      MultiWayIf
+      NamedFieldPuns
+      OverloadedStrings
+      QuasiQuotes
+      RecordWildCards
+      ScopedTypeVariables
+      TupleSections
+      ViewPatterns
+      FlexibleContexts
+      KindSignatures
+      TemplateHaskell
+      TypeFamilies
+  ghc-options: -Wall -threaded -rtsopts -with-rtsopts=-N -haddock -fno-warn-unused-top-binds -fno-warn-orphans
   build-depends:
       aeson
     , aeson-typescript
diff --git a/src/Data/Aeson/TypeScript/Formatting.hs b/src/Data/Aeson/TypeScript/Formatting.hs
--- a/src/Data/Aeson/TypeScript/Formatting.hs
+++ b/src/Data/Aeson/TypeScript/Formatting.hs
@@ -1,8 +1,11 @@
-{-# LANGUAGE QuasiQuotes, OverloadedStrings, TemplateHaskell, RecordWildCards, ScopedTypeVariables, NamedFieldPuns, CPP #-}
+{-# LANGUAGE CPP #-}
 
 module Data.Aeson.TypeScript.Formatting where
 
 import Data.Aeson.TypeScript.Types
+import Data.Function ((&))
+import qualified Data.List as L
+import Data.Maybe
 import Data.String.Interpolate
 import qualified Data.Text as T
 
@@ -17,34 +20,61 @@
 
 -- | Format a single TypeScript declaration. This version accepts a FormattingOptions object in case you want more control over the output.
 formatTSDeclaration :: FormattingOptions -> TSDeclaration -> String
-formatTSDeclaration (FormattingOptions {..}) (TSTypeAlternatives name genericVariables names) =
-  case typeAlternativesFormat of
-    Enum -> [i|#{exportPrefix exportMode}enum #{typeNameModifier name} { #{alternativesEnum} }|]
-    EnumWithType -> [i|#{exportPrefix exportMode}enum #{typeNameModifier name} { #{alternativesEnumWithType} }#{enumType}|]
-    TypeAlias -> [i|#{exportPrefix exportMode}type #{typeNameModifier name}#{getGenericBrackets genericVariables} = #{alternatives};|]
+formatTSDeclaration (FormattingOptions {..}) (TSTypeAlternatives name genericVariables names maybeDoc) =
+  makeDocPrefix maybeDoc <> mainDeclaration
   where
+    mainDeclaration = case typeAlternativesFormat of
+      Enum -> [i|#{exportPrefix exportMode}enum #{typeNameModifier name} { #{alternativesEnum} }|]
+      EnumWithType -> [i|#{exportPrefix exportMode}enum #{typeNameModifier name} { #{alternativesEnumWithType} }#{enumType}|]
+      TypeAlias -> [i|#{exportPrefix exportMode}type #{typeNameModifier name}#{getGenericBrackets genericVariables} = #{alternatives};|]
+
     alternatives = T.intercalate " | " (fmap T.pack names)
     alternativesEnum = T.intercalate ", " $ [toEnumName entry | entry <- T.pack <$> names]
     alternativesEnumWithType = T.intercalate ", " $ [toEnumName entry <> "=" <> entry | entry <- T.pack <$> names]
     enumType = [i|\n\ntype #{name} = keyof typeof #{typeNameModifier name};|] :: T.Text
     toEnumName = T.replace "\"" ""
 
-formatTSDeclaration (FormattingOptions {..}) (TSInterfaceDeclaration interfaceName genericVariables members) =
-  [i|#{exportPrefix exportMode}interface #{modifiedInterfaceName}#{getGenericBrackets genericVariables} {
+formatTSDeclaration (FormattingOptions {..}) (TSInterfaceDeclaration interfaceName genericVariables (filter (not . isNoEmitTypeScriptField) -> members) maybeDoc) =
+  makeDocPrefix maybeDoc <> [i|#{exportPrefix exportMode}interface #{modifiedInterfaceName}#{getGenericBrackets genericVariables} {
 #{ls}
-}|] where ls = T.intercalate "\n" $ fmap T.pack [(replicate numIndentSpaces ' ') <> formatTSField member <> ";"| member <- members]
-          modifiedInterfaceName = (\(li, name) -> li <> interfaceNameModifier name) . splitAt 1 $ interfaceName
+}|] where
+      ls = T.intercalate "\n" $ [indentTo numIndentSpaces (T.pack (formatTSField member <> ";")) | member <- members]
+      modifiedInterfaceName = (\(li, name) -> li <> interfaceNameModifier name) . splitAt 1 $ interfaceName
 
 formatTSDeclaration _ (TSRawDeclaration text) = text
 
+indentTo :: Int -> T.Text -> T.Text
+indentTo numIndentSpaces input = T.intercalate "\n" [padding <> line | line <- T.splitOn "\n" input]
+  where padding = T.replicate numIndentSpaces " "
+
 exportPrefix :: ExportMode -> String
 exportPrefix ExportEach = "export "
 exportPrefix ExportNone = ""
 
 -- | Format a list of TypeScript declarations into a string, suitable for putting directly into a @.d.ts@ file.
 formatTSDeclarations' :: FormattingOptions -> [TSDeclaration] -> String
-formatTSDeclarations' options declarations = T.unpack $ T.intercalate "\n\n" (fmap (T.pack . formatTSDeclaration (validateFormattingOptions options declarations)) declarations)
+formatTSDeclarations' options allDeclarations =
+  declarations & fmap (T.pack . formatTSDeclaration (validateFormattingOptions options declarations))
+               & T.intercalate "\n\n"
+               & T.unpack
+  where
+    removedDeclarations = filter isNoEmitTypeScriptDeclaration allDeclarations
 
+    getDeclarationName :: TSDeclaration -> Maybe String
+    getDeclarationName (TSInterfaceDeclaration {..}) = Just interfaceName
+    getDeclarationName (TSTypeAlternatives {..}) = Just typeName
+    _ = Nothing
+
+    removedDeclarationNames = mapMaybe getDeclarationName removedDeclarations
+
+    removeReferencesToRemovedNames :: [String] -> TSDeclaration -> TSDeclaration
+    removeReferencesToRemovedNames removedNames decl@(TSTypeAlternatives {..}) = decl { alternativeTypes = [x | x <- alternativeTypes, not (x `L.elem` removedNames)] }
+    removeReferencesToRemovedNames _ x = x
+
+    declarations = allDeclarations
+                 & filter (not . isNoEmitTypeScriptDeclaration)
+                 & fmap (removeReferencesToRemovedNames removedDeclarationNames)
+
 validateFormattingOptions :: FormattingOptions -> [TSDeclaration] -> FormattingOptions
 validateFormattingOptions options@FormattingOptions{..} decls
   | typeAlternativesFormat == Enum && isPlainSumType decls = options
@@ -60,8 +90,28 @@
     isPlainSumType ds = (not . any isInterface $ ds) && length ds == 1
 
 formatTSField :: TSField -> String
-formatTSField (TSField optional name typ) = [i|#{name}#{if optional then ("?" :: String) else ""}: #{typ}|]
+formatTSField (TSField optional name typ maybeDoc) = makeDocPrefix maybeDoc <> [i|#{name}#{if optional then ("?" :: String) else ""}: #{typ}|]
 
+makeDocPrefix :: Maybe String -> String
+makeDocPrefix maybeDoc = case maybeDoc of
+  Nothing -> ""
+  Just (T.pack -> text) -> ["// " <> line | line <- T.splitOn "\n" text]
+                        & T.intercalate "\n"
+                        & (<> "\n")
+                        & T.unpack
+
 getGenericBrackets :: [String] -> String
 getGenericBrackets [] = ""
 getGenericBrackets xs = [i|<#{T.intercalate ", " (fmap T.pack xs)}>|]
+
+-- * Support for @no-emit-typescript
+
+noEmitTypeScriptAnnotation :: String
+noEmitTypeScriptAnnotation = "@no-emit-typescript"
+
+isNoEmitTypeScriptField (TSField {fieldDoc=(Just doc)}) = noEmitTypeScriptAnnotation `L.isInfixOf` doc
+isNoEmitTypeScriptField _ = False
+
+isNoEmitTypeScriptDeclaration (TSInterfaceDeclaration {interfaceDoc=(Just doc)}) = noEmitTypeScriptAnnotation `L.isInfixOf` doc
+isNoEmitTypeScriptDeclaration (TSTypeAlternatives {typeDoc=(Just doc)}) = noEmitTypeScriptAnnotation `L.isInfixOf` doc
+isNoEmitTypeScriptDeclaration _ = False
diff --git a/src/Data/Aeson/TypeScript/Instances.hs b/src/Data/Aeson/TypeScript/Instances.hs
--- a/src/Data/Aeson/TypeScript/Instances.hs
+++ b/src/Data/Aeson/TypeScript/Instances.hs
@@ -1,8 +1,4 @@
-{-# LANGUAGE QuasiQuotes #-}
-{-# LANGUAGE OverloadedStrings #-}
 {-# LANGUAGE TemplateHaskell #-}
-{-# LANGUAGE RecordWildCards #-}
-{-# LANGUAGE ScopedTypeVariables #-}
 {-# LANGUAGE ExistentialQuantification #-}
 {-# LANGUAGE FlexibleInstances #-}
 {-# LANGUAGE OverlappingInstances #-}
@@ -89,9 +85,9 @@
 
 instance (TypeScript a, TypeScript b) => TypeScript (Either a b) where
   getTypeScriptType _ = [i|Either<#{getTypeScriptType (Proxy :: Proxy a)}, #{getTypeScriptType (Proxy :: Proxy b)}>|]
-  getTypeScriptDeclarations _ = [TSTypeAlternatives "Either" ["T1", "T2"] ["Left<T1>", "Right<T2>"]
-                               , TSInterfaceDeclaration "Left" ["T"] [TSField False "Left" "T"]
-                               , TSInterfaceDeclaration "Right" ["T"] [TSField False "Right" "T"]
+  getTypeScriptDeclarations _ = [TSTypeAlternatives "Either" ["T1", "T2"] ["Left<T1>", "Right<T2>"] Nothing
+                               , TSInterfaceDeclaration "Left" ["T"] [TSField False "Left" "T" Nothing] Nothing
+                               , TSInterfaceDeclaration "Right" ["T"] [TSField False "Right" "T" Nothing] Nothing
                                ]
   getParentTypes _ = L.nub [ (TSType (Proxy :: Proxy a))
                            , (TSType (Proxy :: Proxy b))
diff --git a/src/Data/Aeson/TypeScript/LegalName.hs b/src/Data/Aeson/TypeScript/LegalName.hs
new file mode 100644
--- /dev/null
+++ b/src/Data/Aeson/TypeScript/LegalName.hs
@@ -0,0 +1,39 @@
+-- | This module defines functions which are useful for determining if
+-- a given name is a legal JavaScript name according to
+-- <https://stackoverflow.com/questions/1661197/what-characters-are-valid-for-javascript-variable-names this post>.
+module Data.Aeson.TypeScript.LegalName where
+
+import Data.Char
+import Data.List.NonEmpty (NonEmpty (..))
+import qualified Data.List.NonEmpty as NonEmpty
+import qualified Data.Set as Set
+
+
+-- | The return type is the illegal characters that are in the name. If the
+-- input has no illegal characters, then you have 'Nothing'.
+checkIllegalNameChars :: NonEmpty Char -> Maybe (NonEmpty Char)
+checkIllegalNameChars (firstChar :| restChars) = NonEmpty.nonEmpty $
+  let
+    legalFirstCategories =
+      Set.fromList
+        [ UppercaseLetter
+        , LowercaseLetter
+        , TitlecaseLetter
+        , ModifierLetter
+        , OtherLetter
+        , LetterNumber
+        ]
+    legalRestCategories =
+      Set.fromList
+        [ NonSpacingMark
+        , SpacingCombiningMark
+        , DecimalNumber
+        , ConnectorPunctuation
+        ]
+        `Set.union` legalFirstCategories
+    isIllegalFirstChar c = not $
+      c `elem` ['$', '_'] || generalCategory c `Set.member` legalFirstCategories
+    isIllegalRestChar c = not $
+      generalCategory c `Set.member` legalRestCategories
+  in
+    filter isIllegalFirstChar [firstChar] <> filter isIllegalRestChar restChars
diff --git a/src/Data/Aeson/TypeScript/Lookup.hs b/src/Data/Aeson/TypeScript/Lookup.hs
--- a/src/Data/Aeson/TypeScript/Lookup.hs
+++ b/src/Data/Aeson/TypeScript/Lookup.hs
@@ -1,17 +1,8 @@
 {-# LANGUAGE CPP #-}
-{-# LANGUAGE QuasiQuotes #-}
-{-# LANGUAGE OverloadedStrings #-}
 {-# LANGUAGE TemplateHaskell #-}
-{-# LANGUAGE RecordWildCards #-}
-{-# LANGUAGE TupleSections #-}
-{-# LANGUAGE ScopedTypeVariables #-}
 {-# LANGUAGE ExistentialQuantification #-}
 {-# LANGUAGE FlexibleInstances #-}
-{-# LANGUAGE NamedFieldPuns #-}
-{-# LANGUAGE MultiWayIf #-}
-{-# LANGUAGE ViewPatterns #-}
 {-# LANGUAGE PolyKinds #-}
-{-# LANGUAGE LambdaCase #-}
 
 module Data.Aeson.TypeScript.Lookup where
 
@@ -46,16 +37,16 @@
   fields <- forM eqns $ \case
 #if MIN_VERSION_template_haskell(2,15,0)
     TySynEqn Nothing (AppT (ConT _) (ConT arg)) result -> do
-      [| TSField False (getTypeScriptType (Proxy :: Proxy $(conT arg))) (getTypeScriptType (Proxy :: Proxy $(return result))) |]
+      [| TSField False (getTypeScriptType (Proxy :: Proxy $(conT arg))) (getTypeScriptType (Proxy :: Proxy $(return result))) Nothing |]
     TySynEqn Nothing (AppT (ConT _) (PromotedT arg)) result -> do
-      [| TSField False (getTypeScriptType (Proxy :: Proxy $(promotedT arg))) (getTypeScriptType (Proxy :: Proxy $(return result))) |]
+      [| TSField False (getTypeScriptType (Proxy :: Proxy $(promotedT arg))) (getTypeScriptType (Proxy :: Proxy $(return result))) Nothing |]
 #else
     TySynEqn [ConT arg] result -> do
-      [| TSField False (getTypeScriptType (Proxy :: Proxy $(conT arg))) (getTypeScriptType (Proxy :: Proxy $(return result))) |]
+      [| TSField False (getTypeScriptType (Proxy :: Proxy $(conT arg))) (getTypeScriptType (Proxy :: Proxy $(return result))) Nothing |]
 #endif
     x -> fail [i|aeson-typescript doesn't know yet how to handle this type family equation: '#{x}'|]
 
-  [| TSInterfaceDeclaration $(TH.stringE $ nameBase name) [] (L.sortBy (compare `on` fieldName) $(listE $ fmap return fields)) |]
+  [| TSInterfaceDeclaration $(TH.stringE $ nameBase name) [] (L.sortBy (compare `on` fieldName) $(listE $ fmap return fields)) Nothing |]
 
 getClosedTypeFamilyImage :: [TySynEqn] -> Q [Type]
 getClosedTypeFamilyImage eqns = do
diff --git a/src/Data/Aeson/TypeScript/Recursive.hs b/src/Data/Aeson/TypeScript/Recursive.hs
--- a/src/Data/Aeson/TypeScript/Recursive.hs
+++ b/src/Data/Aeson/TypeScript/Recursive.hs
@@ -1,14 +1,6 @@
-{-# LANGUAGE QuasiQuotes #-}
-{-# LANGUAGE OverloadedStrings #-}
 {-# LANGUAGE TemplateHaskell #-}
-{-# LANGUAGE RecordWildCards #-}
-{-# LANGUAGE ScopedTypeVariables #-}
 {-# LANGUAGE ExistentialQuantification #-}
 {-# LANGUAGE FlexibleInstances #-}
-{-# LANGUAGE NamedFieldPuns #-}
-{-# LANGUAGE MultiWayIf #-}
-{-# LANGUAGE ViewPatterns #-}
-{-# LANGUAGE LambdaCase #-}
 {-# LANGUAGE PolyKinds #-}
 
 module Data.Aeson.TypeScript.Recursive (
@@ -29,6 +21,7 @@
 import Control.Monad.Writer
 import Data.Aeson.TypeScript.Instances ()
 import Data.Aeson.TypeScript.TH
+import Data.Aeson.TypeScript.Util (nothingOnFail)
 import Data.Bifunctor
 import Data.Function
 import qualified Data.List as L
@@ -135,6 +128,3 @@
     addIfNotPresent :: (Eq a) => a -> [a] -> [a]
     addIfNotPresent x xs | x `L.elem` xs = xs
     addIfNotPresent x xs = x : xs
-
-nothingOnFail :: Q a -> Q (Maybe a)
-nothingOnFail action = recover (return Nothing) (Just <$> action)
diff --git a/src/Data/Aeson/TypeScript/TH.hs b/src/Data/Aeson/TypeScript/TH.hs
--- a/src/Data/Aeson/TypeScript/TH.hs
+++ b/src/Data/Aeson/TypeScript/TH.hs
@@ -1,17 +1,8 @@
 {-# LANGUAGE CPP #-}
-{-# LANGUAGE QuasiQuotes #-}
-{-# LANGUAGE OverloadedStrings #-}
 {-# LANGUAGE TemplateHaskell #-}
-{-# LANGUAGE RecordWildCards #-}
-{-# LANGUAGE TupleSections #-}
-{-# LANGUAGE ScopedTypeVariables #-}
 {-# LANGUAGE ExistentialQuantification #-}
 {-# LANGUAGE FlexibleInstances #-}
-{-# LANGUAGE NamedFieldPuns #-}
-{-# LANGUAGE MultiWayIf #-}
-{-# LANGUAGE ViewPatterns #-}
 {-# LANGUAGE PolyKinds #-}
-{-# LANGUAGE LambdaCase #-}
 
 {-|
 Module:      Data.Aeson.TypeScript.TH
@@ -127,6 +118,7 @@
   , formatTSDeclaration
   , FormattingOptions(..)
   , defaultFormattingOptions
+  , defaultNameFormatter
   , SumTypeFormat(..)
   , ExportMode(..)
 
@@ -194,7 +186,7 @@
         xs -> zip xs allStarConstructors''
   genericVariablesAndSuffixes <- forM varsAndTVars $ \(var, tvar) -> do
     (_, genericInfos) <- runWriterT $ forM_ (datatypeCons datatypeInfo') $ \ci ->
-      forM_ (namesAndTypes options [] ci) $ \(_, typ) -> do
+      forM_ (namesAndTypes options [] ci) $ \(_, _, typ) -> do
         searchForConstraints extraOptions typ var
     return (var, (unifyGenericVariable genericInfos, tvar))
 
@@ -216,10 +208,11 @@
   let typeVariablePreds :: [Pred] = [AppT (ConT ''TypeScript) x | x <- getDataTypeVars dti]
 
   -- Build the declarations
-  (types, (extraDeclsOrGenericInfosInitial <>) -> extraDeclsOrGenericInfos) <- runWriterT $ mapM (handleConstructor options dti genericVariablesAndSuffixes) (datatypeCons dti)
+  (types, (extraDeclsOrGenericInfosInitial <>) -> extraDeclsOrGenericInfos) <- runWriterT $ mapM (handleConstructor extraOptions options dti genericVariablesAndSuffixes) (datatypeCons dti)
   typeDeclaration <- [|TSTypeAlternatives $(TH.stringE $ getTypeName (datatypeName dti))
                                           $(genericVariablesListExpr True genericVariablesAndSuffixes)
-                                          $(listE $ fmap return types)|]
+                                          $(listE $ fmap return types)
+                                          $(tryGetDoc (haddockModifier extraOptions) (datatypeName dti))|]
 
   declarationsFunctionBody <- [| $(return typeDeclaration) : $(listE (fmap return [x | ExtraDecl x <- extraDeclsOrGenericInfos])) |]
 
@@ -243,8 +236,8 @@
   return (mconcat [x | ExtraTopLevelDecs x <- extraDeclsOrGenericInfos] <> inst)
 
 -- | Return a string to go in the top-level type declaration, plus an optional expression containing a declaration
-handleConstructor :: Options -> DatatypeInfo -> [(Name, (Suffix, Var))] -> ConstructorInfo -> WriterT [ExtraDeclOrGenericInfo] Q Exp
-handleConstructor options (DatatypeInfo {..}) genericVariables ci = do
+handleConstructor :: ExtraTypeScriptOptions -> Options -> DatatypeInfo -> [(Name, (Suffix, Var))] -> ConstructorInfo -> WriterT [ExtraDeclOrGenericInfo] Q Exp
+handleConstructor (ExtraTypeScriptOptions {..}) options (DatatypeInfo {..}) genericVariables ci = do
   if | (length datatypeCons == 1) && not (getTagSingleConstructors options) -> do
          writeSingleConstructorEncoding
          brackets <- lift $ getBracketsExpression False genericVariables
@@ -269,7 +262,7 @@
          lift [|$(TH.stringE interfaceName) <> $(return brackets)|]
      | otherwise -> do
          tagField :: [Exp] <- lift $ case sumEncoding options of
-           TaggedObject tagFieldName _ -> (: []) <$> [|TSField False $(TH.stringE tagFieldName) $(TH.stringE [i|"#{constructorNameToUse options ci}"|])|]
+           TaggedObject tagFieldName _ -> (: []) <$> [|TSField False $(TH.stringE tagFieldName) $(TH.stringE [i|"#{constructorNameToUse options ci}"|]) Nothing|]
            _ -> return []
 
          tsFields <- getTSFields
@@ -294,7 +287,8 @@
             _ -> getTypeAsStringExp typ
           alternatives <- lift [|TSTypeAlternatives $(TH.stringE interfaceName)
                                                     $(genericVariablesListExpr True genericVariables)
-                                                    [$(return stringExp)]|]
+                                                    [$(return stringExp)]
+                                                    $(tryGetDoc haddockModifier (constructorName ci))|]
           tell [ExtraDecl alternatives]
 #endif
 
@@ -309,21 +303,24 @@
     tupleEncoding =
       lift [|TSTypeAlternatives $(TH.stringE interfaceName)
                                 $(genericVariablesListExpr True genericVariables)
-                                [getTypeScriptType (Proxy :: Proxy $(return (contentsTupleTypeSubstituted genericVariables ci)))]|]
+                                [getTypeScriptType (Proxy :: Proxy $(return (contentsTupleTypeSubstituted genericVariables ci)))]
+                                $(tryGetDoc haddockModifier (constructorName ci))|]
 
     assembleInterfaceDeclaration members = [|TSInterfaceDeclaration $(TH.stringE interfaceName)
                                                                     $(genericVariablesListExpr True genericVariables)
-                                                                    $(return members)|]
+                                                                    $(return members)
+                                                                    $(tryGetDoc haddockModifier (constructorName ci))|]
 
     getTSFields :: WriterT [ExtraDeclOrGenericInfo] Q [Exp]
-    getTSFields = forM (namesAndTypes options genericVariables ci) $ \(nameString, typ) -> do
+    getTSFields = forM (namesAndTypes options genericVariables ci) $ \(name, nameString, typ) -> do
       (fieldTyp, optAsBool) <- lift $ case typ of
         (AppT (ConT name) t) | name == ''Maybe && not (omitNothingFields options) ->
           ( , ) <$> [|$(getTypeAsStringExp t) <> " | null"|] <*> getOptionalAsBoolExp t
         _ -> ( , ) <$> getTypeAsStringExp typ <*> getOptionalAsBoolExp typ
-      lift $ [| TSField $(return optAsBool) $(TH.stringE nameString) $(return fieldTyp) |]
 
-    isSingleRecordConstructor (constructorVariant -> RecordConstructor [x]) = True
+      lift [| TSField $(return optAsBool) $(TH.stringE nameString) $(return fieldTyp) $(tryGetDoc haddockModifier name) |]
+
+    isSingleRecordConstructor (constructorVariant -> RecordConstructor [_]) = True
     isSingleRecordConstructor _ = False
 
 -- * Convenience functions
diff --git a/src/Data/Aeson/TypeScript/Transform.hs b/src/Data/Aeson/TypeScript/Transform.hs
--- a/src/Data/Aeson/TypeScript/Transform.hs
+++ b/src/Data/Aeson/TypeScript/Transform.hs
@@ -1,17 +1,8 @@
 {-# LANGUAGE CPP #-}
-{-# LANGUAGE QuasiQuotes #-}
-{-# LANGUAGE OverloadedStrings #-}
 {-# LANGUAGE TemplateHaskell #-}
-{-# LANGUAGE RecordWildCards #-}
-{-# LANGUAGE TupleSections #-}
-{-# LANGUAGE ScopedTypeVariables #-}
 {-# LANGUAGE ExistentialQuantification #-}
 {-# LANGUAGE FlexibleInstances #-}
-{-# LANGUAGE NamedFieldPuns #-}
-{-# LANGUAGE MultiWayIf #-}
-{-# LANGUAGE ViewPatterns #-}
 {-# LANGUAGE PolyKinds #-}
-{-# LANGUAGE LambdaCase #-}
 
 
 module Data.Aeson.TypeScript.Transform (
diff --git a/src/Data/Aeson/TypeScript/TypeManipulation.hs b/src/Data/Aeson/TypeScript/TypeManipulation.hs
--- a/src/Data/Aeson/TypeScript/TypeManipulation.hs
+++ b/src/Data/Aeson/TypeScript/TypeManipulation.hs
@@ -1,17 +1,8 @@
 {-# LANGUAGE CPP #-}
-{-# LANGUAGE QuasiQuotes #-}
-{-# LANGUAGE OverloadedStrings #-}
 {-# LANGUAGE TemplateHaskell #-}
-{-# LANGUAGE RecordWildCards #-}
-{-# LANGUAGE TupleSections #-}
-{-# LANGUAGE ScopedTypeVariables #-}
 {-# LANGUAGE ExistentialQuantification #-}
 {-# LANGUAGE FlexibleInstances #-}
-{-# LANGUAGE NamedFieldPuns #-}
-{-# LANGUAGE MultiWayIf #-}
-{-# LANGUAGE ViewPatterns #-}
 {-# LANGUAGE PolyKinds #-}
-{-# LANGUAGE LambdaCase #-}
 
 module Data.Aeson.TypeScript.TypeManipulation (
   searchForConstraints
diff --git a/src/Data/Aeson/TypeScript/Types.hs b/src/Data/Aeson/TypeScript/Types.hs
--- a/src/Data/Aeson/TypeScript/Types.hs
+++ b/src/Data/Aeson/TypeScript/Types.hs
@@ -1,8 +1,4 @@
-{-# LANGUAGE QuasiQuotes #-}
-{-# LANGUAGE OverloadedStrings #-}
 {-# LANGUAGE TemplateHaskell #-}
-{-# LANGUAGE RecordWildCards #-}
-{-# LANGUAGE ScopedTypeVariables #-}
 {-# LANGUAGE ExistentialQuantification #-}
 {-# LANGUAGE PolyKinds #-}
 {-# LANGUAGE StandaloneDeriving #-}
@@ -10,8 +6,12 @@
 module Data.Aeson.TypeScript.Types where
 
 import qualified Data.Aeson as A
+import Data.Aeson.TypeScript.LegalName
+import Data.Function ((&))
+import qualified Data.List.NonEmpty as NonEmpty
 import Data.Proxy
 import Data.String
+import qualified Data.Text as T
 import Data.Typeable
 import Language.Haskell.TH
 
@@ -84,16 +84,22 @@
 
 data TSDeclaration = TSInterfaceDeclaration { interfaceName :: String
                                             , interfaceGenericVariables :: [String]
-                                            , interfaceMembers :: [TSField] }
+                                            , interfaceMembers :: [TSField]
+                                            , interfaceDoc :: Maybe String }
                    | TSTypeAlternatives { typeName :: String
                                         , typeGenericVariables :: [String]
-                                        , alternativeTypes :: [String]}
+                                        , alternativeTypes :: [String]
+                                        , typeDoc :: Maybe String }
                    | TSRawDeclaration { text :: String }
   deriving (Show, Eq, Ord)
 
-data TSField = TSField { fieldOptional :: Bool
-                       , fieldName :: String
-                       , fieldType :: String } deriving (Show, Eq, Ord)
+data TSField = TSField
+  { fieldOptional :: Bool
+  , fieldName :: String
+  , fieldType :: String
+  , fieldDoc :: Maybe String
+  -- ^ Haddock documentation for the field, if present
+  } deriving (Show, Eq, Ord)
 
 newtype TSString a = TSString { unpackTSString :: String } deriving Show
 
@@ -131,12 +137,30 @@
 defaultFormattingOptions :: FormattingOptions
 defaultFormattingOptions = FormattingOptions
   { numIndentSpaces = 2
-  , interfaceNameModifier = id
-  , typeNameModifier = id
+  , interfaceNameModifier = defaultNameFormatter
+  , typeNameModifier = defaultNameFormatter
   , exportMode = ExportNone
   , typeAlternativesFormat = TypeAlias
   }
 
+-- | The 'defaultNameFormatter' in the 'FormattingOptions' checks to see if
+-- the name is a legal TypeScript name. If it is not, then it throws
+-- a runtime error.
+defaultNameFormatter :: String -> String
+defaultNameFormatter str =
+  case NonEmpty.nonEmpty str of
+    Nothing ->
+      error "Name cannot be empty"
+    Just nameChars ->
+      case checkIllegalNameChars nameChars of
+        Just badChars ->
+          error $ concat
+            [ "The name ", str, " contains illegal characters: ", NonEmpty.toList badChars
+            , "\nConsider setting a default name formatter that replaces these characters, or renaming the type."
+            ]
+        Nothing ->
+          str
+
 -- | Convenience typeclass class you can use to "attach" a set of Aeson encoding options to a type.
 class HasJSONOptions a where
   getJSONOptions :: (Proxy a) -> A.Options
@@ -178,11 +202,24 @@
 
 data ExtraTypeScriptOptions = ExtraTypeScriptOptions {
   typeFamiliesToMapToTypeScript :: [Name]
+
   , keyType :: Maybe String
+
+  -- | Function which is applied to all Haddocks we read in.
+  -- By default, just drops leading whitespace from each line.
+  , haddockModifier :: String -> String
   }
 
 defaultExtraTypeScriptOptions :: ExtraTypeScriptOptions
-defaultExtraTypeScriptOptions = ExtraTypeScriptOptions [] Nothing
+defaultExtraTypeScriptOptions = ExtraTypeScriptOptions [] Nothing stripStartEachLine
+  where
+    stripStartEachLine :: String -> String
+    stripStartEachLine s = s
+                         & T.pack
+                         & T.splitOn "\n"
+                         & fmap T.stripStart
+                         & T.intercalate "\n"
+                         & T.unpack
 
 data ExtraDeclOrGenericInfo = ExtraDecl Exp
                             | ExtraGeneric GenericInfo
diff --git a/src/Data/Aeson/TypeScript/Util.hs b/src/Data/Aeson/TypeScript/Util.hs
--- a/src/Data/Aeson/TypeScript/Util.hs
+++ b/src/Data/Aeson/TypeScript/Util.hs
@@ -1,14 +1,7 @@
 {-# LANGUAGE CPP #-}
-{-# LANGUAGE QuasiQuotes #-}
-{-# LANGUAGE OverloadedStrings #-}
 {-# LANGUAGE TemplateHaskell #-}
-{-# LANGUAGE RecordWildCards #-}
-{-# LANGUAGE ScopedTypeVariables #-}
 {-# LANGUAGE ExistentialQuantification #-}
 {-# LANGUAGE FlexibleInstances #-}
-{-# LANGUAGE NamedFieldPuns #-}
-{-# LANGUAGE MultiWayIf #-}
-{-# LANGUAGE ViewPatterns #-}
 {-# LANGUAGE PolyKinds #-}
 
 module Data.Aeson.TypeScript.Util where
@@ -148,14 +141,14 @@
 mkInstance = InstanceD
 #endif
 
-namesAndTypes :: Options -> [(Name, (Suffix, Var))] -> ConstructorInfo -> [(String, Type)]
+namesAndTypes :: Options -> [(Name, (Suffix, Var))] -> ConstructorInfo -> [(Name, String, Type)]
 namesAndTypes options genericVariables ci = case constructorVariant ci of
-  RecordConstructor names -> zip (fmap ((fieldLabelModifier options) . lastNameComponent') names) (constructorFields ci)
+  RecordConstructor names -> zip3 names (fmap ((fieldLabelModifier options) . lastNameComponent') names) (constructorFields ci)
   _ -> case sumEncoding options of
     TaggedObject _ contentsFieldName
       | isConstructorNullary ci -> []
-      | otherwise -> [(contentsFieldName, contentsTupleTypeSubstituted genericVariables ci)]
-    _ -> [(constructorNameToUse options ci, contentsTupleTypeSubstituted genericVariables ci)]
+      | otherwise -> [(mkName "", contentsFieldName, contentsTupleTypeSubstituted genericVariables ci)]
+    _ -> [(constructorName ci, constructorNameToUse options ci, contentsTupleTypeSubstituted genericVariables ci)]
 
 constructorNameToUse :: Options -> ConstructorInfo -> String
 constructorNameToUse options ci = (constructorTagModifier options) $ lastNameComponent' (constructorName ci)
@@ -224,3 +217,20 @@
 isStarType :: Type -> Maybe Name
 isStarType (SigT (VarT n) StarT) = Just n
 isStarType _ = Nothing
+
+nothingOnFail :: Q a -> Q (Maybe a)
+nothingOnFail action = recover (return Nothing) (Just <$> action)
+
+tryGetDoc :: (String -> String) -> Name -> Q Exp
+tryGetDoc haddockModifier n = do
+#if MIN_VERSION_template_haskell(2,18,0)
+  maybeDoc <- nothingOnFail (getDoc (DeclDoc n)) >>= \case
+    Just (Just doc) -> return $ Just $ Just $ haddockModifier doc
+    x -> return x
+#else
+  let maybeDoc = Nothing
+#endif
+
+  case maybeDoc of
+    Just (Just doc) -> [|Just $(TH.stringE doc)|]
+    _ -> [|Nothing|]
diff --git a/test/Basic.hs b/test/Basic.hs
--- a/test/Basic.hs
+++ b/test/Basic.hs
@@ -1,17 +1,3 @@
-{-# LANGUAGE QuasiQuotes #-}
-{-# LANGUAGE OverloadedStrings #-}
-{-# LANGUAGE TemplateHaskell #-}
-{-# LANGUAGE RecordWildCards #-}
-{-# LANGUAGE ScopedTypeVariables #-}
-{-# LANGUAGE NamedFieldPuns #-}
-{-# LANGUAGE KindSignatures #-}
-{-# LANGUAGE ConstraintKinds #-}
-{-# LANGUAGE DataKinds #-}
-{-# LANGUAGE GADTs #-}
-{-# LANGUAGE TypeFamilies #-}
-{-# LANGUAGE FlexibleContexts #-}
-{-# LANGUAGE UndecidableInstances #-}
-{-# OPTIONS_GHC -fno-warn-unused-top-binds #-}
 
 module Basic (tests) where
 
@@ -36,12 +22,14 @@
   describe "tagSingleConstructors and constructorTagModifier" $ do
     it [i|Works with a normal unit|] $ do
       (getTypeScriptDeclarations (Proxy :: Proxy Unit1)) `shouldBe` ([
-        TSTypeAlternatives "Unit1" [] ["IUnit1"]
-        , TSTypeAlternatives "IUnit1" [] ["void[]"]
+        TSTypeAlternatives "Unit1" [] ["IUnit1"] Nothing
+        , TSTypeAlternatives "IUnit1" [] ["void[]"] Nothing
         ])
 
     it [i|Works with a unit with constructorTagModifier|] $ do
-      (getTypeScriptDeclarations (Proxy :: Proxy Unit2)) `shouldBe` ([])
+      (getTypeScriptDeclarations (Proxy :: Proxy Unit2)) `shouldBe` ([
+        TSTypeAlternatives "Unit2" [] ["\"foo\""] Nothing
+        ])
 
 
 main :: IO ()
diff --git a/test/ClosedTypeFamilies.hs b/test/ClosedTypeFamilies.hs
--- a/test/ClosedTypeFamilies.hs
+++ b/test/ClosedTypeFamilies.hs
@@ -1,18 +1,5 @@
-{-# LANGUAGE QuasiQuotes #-}
-{-# LANGUAGE OverloadedStrings #-}
-{-# LANGUAGE TemplateHaskell #-}
-{-# LANGUAGE RecordWildCards #-}
-{-# LANGUAGE ScopedTypeVariables #-}
-{-# LANGUAGE NamedFieldPuns #-}
-{-# LANGUAGE KindSignatures #-}
-{-# LANGUAGE ConstraintKinds #-}
-{-# LANGUAGE DataKinds #-}
-{-# LANGUAGE GADTs #-}
-{-# LANGUAGE TypeFamilies #-}
 {-# LANGUAGE TypeFamilyDependencies #-}
-{-# LANGUAGE FlexibleContexts #-}
 {-# LANGUAGE UndecidableInstances #-}
-{-# OPTIONS_GHC -fno-warn-unused-top-binds #-}
 
 module ClosedTypeFamilies (tests) where
 
@@ -53,38 +40,38 @@
     it [i|makes the declaration and types correctly|] $ do
       (getTypeScriptDeclarationsRecursively (Proxy :: Proxy (Simple T))) `shouldBe` ([
         TSInterfaceDeclaration "DeployEnvironment2" [] [
-          TSField False "\"k8s_env\"" "\"k8s\""
-          , TSField False "\"single_node_env\"" "\"single\""
-          , TSField False "T" "void"
-          ]
-        , TSTypeAlternatives "ISimple" ["T extends keyof DeployEnvironment2"] ["DeployEnvironment2[T]"]
-        , TSTypeAlternatives "Simple" ["T extends keyof DeployEnvironment2"] ["ISimple<T>"]
+          TSField False "\"k8s_env\"" "\"k8s\"" Nothing
+          , TSField False "\"single_node_env\"" "\"single\"" Nothing
+          , TSField False "T" "void" Nothing
+          ] Nothing
+        , TSTypeAlternatives "ISimple" ["T extends keyof DeployEnvironment2"] ["DeployEnvironment2[T]"] Nothing
+        , TSTypeAlternatives "Simple" ["T extends keyof DeployEnvironment2"] ["ISimple<T>"] Nothing
         ])
 
   describe "Complicated Beam-like user type" $ do
     it [i|makes the declaration and types correctly|] $ do
       (getTypeScriptDeclarations (Proxy :: Proxy (UserT T Identity))) `shouldBe` ([
-        TSTypeAlternatives "UserT" ["T extends keyof DeployEnvironment"] ["IUser<T>"]
+        TSTypeAlternatives "UserT" ["T extends keyof DeployEnvironment"] ["IUser<T>"] Nothing
         , TSInterfaceDeclaration "IUser" ["T extends keyof DeployEnvironment"] [
-            TSField False "_userUsername" "string"
-            , TSField False "_userCreatedAt" "number"
-            , TSField False "_userDeployEnvironment" "DeployEnvironment[T]"
-            ]
+            TSField False "_userUsername" "string" Nothing
+            , TSField False "_userCreatedAt" "number" Nothing
+            , TSField False "_userDeployEnvironment" "DeployEnvironment[T]" Nothing
+            ] Nothing
         ])
 
     it [i|get the declarations recursively|] $ do
       (getTypeScriptDeclarationsRecursively (Proxy :: Proxy (UserT T Identity))) `shouldBe` ([
         TSInterfaceDeclaration "DeployEnvironment" [] [
-          TSField False "\"k8s_env\"" "\"k8s\""
-          , TSField False "\"single_node_env\"" "\"single\""
-          , TSField False "T" "void"
-          ]
+          TSField False "\"k8s_env\"" "\"k8s\"" Nothing
+          , TSField False "\"single_node_env\"" "\"single\"" Nothing
+          , TSField False "T" "void" Nothing
+          ] Nothing
         , TSInterfaceDeclaration "IUser" ["T extends keyof DeployEnvironment"] [
-            TSField False "_userUsername" "string"
-            , TSField False "_userCreatedAt" "number"
-            , TSField False "_userDeployEnvironment" "DeployEnvironment[T]"
-            ]
-        , TSTypeAlternatives "UserT" ["T extends keyof DeployEnvironment"] ["IUser<T>"]
+            TSField False "_userUsername" "string" Nothing
+            , TSField False "_userCreatedAt" "number" Nothing
+            , TSField False "_userDeployEnvironment" "DeployEnvironment[T]" Nothing
+            ] Nothing
+        , TSTypeAlternatives "UserT" ["T extends keyof DeployEnvironment"] ["IUser<T>"] Nothing
         ])
 
 main :: IO ()
diff --git a/test/Formatting.hs b/test/Formatting.hs
--- a/test/Formatting.hs
+++ b/test/Formatting.hs
@@ -1,34 +1,79 @@
-{-# LANGUAGE ScopedTypeVariables #-}
-{-# LANGUAGE TemplateHaskell #-}
+{-# LANGUAGE CPP #-}
 {-# LANGUAGE TypeApplications #-}
-{-# LANGUAGE QuasiQuotes #-}
 
 module Formatting (tests) where
 
+import Control.Exception
 import Data.Aeson (defaultOptions)
 import Data.Aeson.TypeScript.TH
-import Data.Aeson.TypeScript.Types
 import Data.Proxy
 import Data.String.Interpolate
 import Test.Hspec
 
-data D = S | F deriving (Eq, Show)
 
+data D = S | F deriving (Eq, Show)
 $(deriveTypeScript defaultOptions ''D)
 
+data PrimeInType' = PrimeInType
+$(deriveTypeScript defaultOptions ''PrimeInType')
+
+data PrimeInConstr = PrimeInConstr'
+$(deriveTypeScript defaultOptions ''PrimeInConstr)
+
+data FooBar =
+  Foo {
+    -- | @no-emit-typescript
+    recordString :: String
+    , recordInt :: Int
+    }
+  |
+  -- | @no-emit-typescript
+  Bar {
+      barInt :: Int
+  }
+$(deriveTypeScript defaultOptions ''FooBar)
+
+data NormalConstructors =
+  -- | @no-emit-typescript
+  Con1 String
+  | Con2 Int
+$(deriveTypeScript defaultOptions ''NormalConstructors)
+
 tests :: Spec
-tests = do
-  describe "Formatting" $
-    describe "when given a Sum Type" $ do
-      describe "and the TypeAlias format option is set" $
-        it "should generate a TS string literal type" $
-          formatTSDeclarations' defaultFormattingOptions (getTypeScriptDeclarations @D Proxy) `shouldBe`
-            [i|type D = "S" | "F";|]
-      describe "and the Enum format option is set" $
-        it "should generate a TS Enum" $
-          formatTSDeclarations' (defaultFormattingOptions { typeAlternativesFormat = Enum }) (getTypeScriptDeclarations @D Proxy) `shouldBe`
-            [i|enum D { S, F }|]
-      describe "and the EnumWithType format option is set" $
-        it "should generate a TS Enum with a type declaration" $
-          formatTSDeclarations' (defaultFormattingOptions { typeAlternativesFormat = EnumWithType }) (getTypeScriptDeclarations @D Proxy) `shouldBe`
-            [i|enum DEnum { S="S", F="F" }\n\ntype D = keyof typeof DEnum;|]
+tests = describe "Formatting" $ do
+  describe "when given a Sum Type" $ do
+    describe "and the TypeAlias format option is set" $
+      it "should generate a TS string literal type" $
+        formatTSDeclarations' defaultFormattingOptions (getTypeScriptDeclarations @D Proxy) `shouldBe`
+          [i|type D = "S" | "F";|]
+
+    describe "and the Enum format option is set" $
+      it "should generate a TS Enum" $
+        formatTSDeclarations' (defaultFormattingOptions { typeAlternativesFormat = Enum }) (getTypeScriptDeclarations @D Proxy) `shouldBe`
+          [i|enum D { S, F }|]
+
+    describe "and the EnumWithType format option is set" $
+      it "should generate a TS Enum with a type declaration" $
+        formatTSDeclarations' (defaultFormattingOptions { typeAlternativesFormat = EnumWithType }) (getTypeScriptDeclarations @D Proxy) `shouldBe`
+          [i|enum DEnum { S="S", F="F" }\n\ntype D = keyof typeof DEnum;|]
+
+  describe "when the name has an apostrophe" $ do
+    describe "in the type" $ do
+      it "throws an error" $ do
+        evaluate (formatTSDeclarations' defaultFormattingOptions (getTypeScriptDeclarations @PrimeInType' Proxy)) `shouldThrow` anyErrorCall
+
+    describe "in the constructor" $ do
+      it "throws an error" $ do
+        evaluate (formatTSDeclarations' defaultFormattingOptions (getTypeScriptDeclarations @PrimeInConstr Proxy)) `shouldThrow` anyErrorCall
+
+#if MIN_VERSION_template_haskell(2,18,0)
+  describe "when @no-emit-typescript is present" $ do
+    it [i|works on records and constructors of record types|] $ do
+      formatTSDeclarations' defaultFormattingOptions (getTypeScriptDeclarations @FooBar Proxy) `shouldBe` [i|type FooBar = IFoo;\n\ninterface IFoo {\n  tag: "Foo";\n  recordInt: number;\n}|]
+
+    it [i|works on normal constructors|] $ do
+      formatTSDeclarations' defaultFormattingOptions (getTypeScriptDeclarations @NormalConstructors Proxy) `shouldBe` [i|type NormalConstructors = ICon2;\n\ninterface ICon2 {\n  tag: "Con2";\n  contents: number;\n}|]
+#endif
+
+main :: IO ()
+main = hspec tests
diff --git a/test/Generic.hs b/test/Generic.hs
--- a/test/Generic.hs
+++ b/test/Generic.hs
@@ -1,18 +1,3 @@
-{-# LANGUAGE QuasiQuotes #-}
-{-# LANGUAGE OverloadedStrings #-}
-{-# LANGUAGE TemplateHaskell #-}
-{-# LANGUAGE RecordWildCards #-}
-{-# LANGUAGE ScopedTypeVariables #-}
-{-# LANGUAGE NamedFieldPuns #-}
-{-# LANGUAGE KindSignatures #-}
-{-# LANGUAGE ConstraintKinds #-}
-{-# LANGUAGE DataKinds #-}
-{-# LANGUAGE GADTs #-}
-{-# LANGUAGE TypeFamilies #-}
-{-# LANGUAGE TypeFamilyDependencies #-}
-{-# LANGUAGE FlexibleContexts #-}
-{-# LANGUAGE UndecidableInstances #-}
-{-# OPTIONS_GHC -fno-warn-unused-top-binds #-}
 
 module Generic (tests) where
 
@@ -44,38 +29,32 @@
 tests = describe "Generic instances" $ do
   it [i|Complex makes the declaration and types correctly|] $ do
     (getTypeScriptDeclarationsRecursively (Proxy :: Proxy (Complex String))) `shouldBe` [
-      TSInterfaceDeclaration {interfaceName = "IProduct", interfaceGenericVariables = ["T"], interfaceMembers = [TSField {fieldOptional = False, fieldName = "tag", fieldType = "\"Product\""},TSField {fieldOptional = False, fieldName = "contents", fieldType = "[number, T]"}]}
-      ,TSInterfaceDeclaration {interfaceName = "IUnary", interfaceGenericVariables = ["T"], interfaceMembers = [TSField {fieldOptional = False, fieldName = "tag", fieldType = "\"Unary\""},TSField {fieldOptional = False, fieldName = "contents", fieldType = "number"}]}
-      ,TSTypeAlternatives {typeName = "Complex", typeGenericVariables = ["T"], alternativeTypes = ["IProduct<T>","IUnary<T>"]}
+      TSInterfaceDeclaration "IProduct" ["T"] [TSField False "tag" "\"Product\"" Nothing, TSField False "contents" "[number, T]" Nothing] Nothing
+      ,TSInterfaceDeclaration "IUnary" ["T"] [TSField False "tag" "\"Unary\"" Nothing, TSField False "contents" "number" Nothing] Nothing
+      ,TSTypeAlternatives "Complex" ["T"] ["IProduct<T>","IUnary<T>"] Nothing
       ]
 
   it [i|Complex2 makes the declaration and types correctly|] $ do
     (getTypeScriptDeclarationsRecursively (Proxy :: Proxy (Complex2 String))) `shouldBe` [
-      TSTypeAlternatives {typeName = "Complex2", typeGenericVariables = ["T"], alternativeTypes = ["IProduct2<T>"]}
-      ,TSTypeAlternatives {typeName = "IProduct2", typeGenericVariables = ["T"], alternativeTypes = ["[number, T]"]}
+      TSTypeAlternatives "Complex2" ["T"] ["IProduct2<T>"] Nothing
+      ,TSTypeAlternatives "IProduct2" ["T"] ["[number, T]"] Nothing
       ]
 
   it [i|Complex3 makes the declaration and types correctly|] $ do
     (getTypeScriptDeclarationsRecursively (Proxy :: Proxy (Complex3 String))) `shouldBe` [
-      TSInterfaceDeclaration {interfaceName = "IProduct3", interfaceGenericVariables = ["T"], interfaceMembers = [
-                                 TSField {fieldOptional = False, fieldName = "record3", fieldType = "T[]"}
-                                 ]}
-      ,TSTypeAlternatives {typeName = "Complex3", typeGenericVariables = ["T"], alternativeTypes = ["IProduct3<T>"]}
+      TSInterfaceDeclaration "IProduct3" ["T"] [TSField False "record3" "T[]" Nothing] Nothing
+      ,TSTypeAlternatives "Complex3" ["T"] ["IProduct3<T>"] Nothing
       ]
 
     (getTypeScriptDeclarationsRecursively (Proxy :: Proxy (Complex3 Int))) `shouldBe` [
-      TSInterfaceDeclaration {interfaceName = "IProduct3", interfaceGenericVariables = ["T"], interfaceMembers = [
-                                 TSField {fieldOptional = False, fieldName = "record3", fieldType = "T[]"}
-                                 ]}
-      ,TSTypeAlternatives {typeName = "Complex3", typeGenericVariables = ["T"], alternativeTypes = ["IProduct3<T>"]}
+      TSInterfaceDeclaration "IProduct3" ["T"] [TSField False "record3" "T[]" Nothing] Nothing
+      ,TSTypeAlternatives "Complex3" ["T"] ["IProduct3<T>"] Nothing
       ]
 
   it [i|Complex4 makes the declaration and types correctly|] $ do
     (getTypeScriptDeclarationsRecursively (Proxy :: Proxy (Complex4 String))) `shouldBe` [
-      TSInterfaceDeclaration {interfaceName = "IProduct4", interfaceGenericVariables = ["T"], interfaceMembers = [
-                                 TSField {fieldOptional = False, fieldName = "record4", fieldType = "{[k in string]?: T}"}
-                                 ]}
-      ,TSTypeAlternatives {typeName = "Complex4", typeGenericVariables = ["T"], alternativeTypes = ["IProduct4<T>"]}
+      TSInterfaceDeclaration "IProduct4" ["T"] [TSField False "record4" "{[k in string]?: T}" Nothing] Nothing
+      ,TSTypeAlternatives "Complex4" ["T"] ["IProduct4<T>"] Nothing
       ]
 
 main :: IO ()
diff --git a/test/GetDoc.hs b/test/GetDoc.hs
new file mode 100644
--- /dev/null
+++ b/test/GetDoc.hs
@@ -0,0 +1,33 @@
+
+module GetDoc (tests) where
+
+import Data.Aeson as A
+import Data.Aeson.TypeScript.TH
+import Data.Aeson.TypeScript.Types
+import Data.Proxy
+import Data.String.Interpolate
+import Prelude hiding (Double)
+import Test.Hspec
+
+
+-- | OneField type doc
+data OneField =
+  -- | OneField constructor doc
+  OneField {
+    -- | This is a simple string
+    simpleString :: String
+    }
+$(deriveTypeScript A.defaultOptions ''OneField)
+
+tests :: SpecWith ()
+tests = describe "getDoc tests" $ do
+  it [i|Works with a simple record type|] $ do
+    (getTypeScriptDeclarations (Proxy :: Proxy OneField)) `shouldBe` ([
+      TSTypeAlternatives "OneField" [] ["IOneField"] (Just "OneField type doc")
+      , TSInterfaceDeclaration "IOneField" [] [
+          TSField False "simpleString" "string" (Just "This is a simple string")
+          ] (Just "OneField constructor doc")
+      ])
+
+main :: IO ()
+main = hspec tests
diff --git a/test/HigherKind.hs b/test/HigherKind.hs
--- a/test/HigherKind.hs
+++ b/test/HigherKind.hs
@@ -1,17 +1,3 @@
-{-# LANGUAGE QuasiQuotes #-}
-{-# LANGUAGE OverloadedStrings #-}
-{-# LANGUAGE TemplateHaskell #-}
-{-# LANGUAGE RecordWildCards #-}
-{-# LANGUAGE ScopedTypeVariables #-}
-{-# LANGUAGE NamedFieldPuns #-}
-{-# LANGUAGE KindSignatures #-}
-{-# LANGUAGE ConstraintKinds #-}
-{-# LANGUAGE DataKinds #-}
-{-# LANGUAGE GADTs #-}
-{-# LANGUAGE TypeFamilies #-}
-{-# LANGUAGE FlexibleContexts #-}
-{-# LANGUAGE UndecidableInstances #-}
-{-# OPTIONS_GHC -fno-warn-unused-top-binds #-}
 
 module HigherKind (tests) where
 
@@ -50,8 +36,8 @@
   describe "Kind * -> *" $ do
     it [i|makes the declaration and types correctly|] $ do
       (getTypeScriptDeclarations (Proxy :: Proxy (HigherKind T))) `shouldBe` ([
-        TSTypeAlternatives "HigherKind" ["T"] ["IHigherKind<T>"],
-        TSInterfaceDeclaration "IHigherKind" ["T"] [TSField False "higherKindList" "T[]"]
+        TSTypeAlternatives "HigherKind" ["T"] ["IHigherKind<T>"] Nothing,
+        TSInterfaceDeclaration "IHigherKind" ["T"] [TSField False "higherKindList" "T[]" Nothing] Nothing
         ])
 
       (getTypeScriptType (Proxy :: Proxy (HigherKind Int))) `shouldBe` "HigherKind<number>"
@@ -59,23 +45,23 @@
 
     it [i|works when referenced in another type|] $ do
       (getTypeScriptDeclarations (Proxy :: Proxy Foo)) `shouldBe` ([
-        TSTypeAlternatives "Foo" [] ["IFoo"],
-        TSInterfaceDeclaration "IFoo" [] [TSField False "fooString" "string"
-                                         , TSField False "fooHigherKindReference" "HigherKind<string>"]
+        TSTypeAlternatives "Foo" [] ["IFoo"] Nothing,
+        TSInterfaceDeclaration "IFoo" [] [TSField False "fooString" "string" Nothing
+                                         , TSField False "fooHigherKindReference" "HigherKind<string>" Nothing] Nothing
         ])
 
     it [i|works with an interface inside|] $ do
       (getTypeScriptDeclarations (Proxy :: Proxy (HigherKindWithUnary T))) `shouldBe` ([
-        TSTypeAlternatives "HigherKindWithUnary" ["T"] ["IUnary<T>"],
-        TSTypeAlternatives "IUnary" ["T"] ["number"]
+        TSTypeAlternatives "HigherKindWithUnary" ["T"] ["IUnary<T>"] Nothing,
+        TSTypeAlternatives "IUnary" ["T"] ["number"] Nothing
         ])
 
   describe "Kind * -> * -> *" $ do
     it [i|makes the declaration and type correctly|] $ do
       (getTypeScriptDeclarations (Proxy :: Proxy (DoubleHigherKind T1 T2))) `shouldBe` ([
-        TSTypeAlternatives "DoubleHigherKind" ["T1","T2"] ["IDoubleHigherKind<T1, T2>"],
-        TSInterfaceDeclaration "IDoubleHigherKind" ["T1","T2"] [TSField False "someList" "T2[]"
-                                                               , TSField False "higherKindThing" "HigherKind<T1>"]
+        TSTypeAlternatives "DoubleHigherKind" ["T1","T2"] ["IDoubleHigherKind<T1, T2>"] Nothing,
+        TSInterfaceDeclaration "IDoubleHigherKind" ["T1","T2"] [TSField False "someList" "T2[]" Nothing
+                                                               , TSField False "higherKindThing" "HigherKind<T1>" Nothing] Nothing
         ])
 
       (getTypeScriptType (Proxy :: Proxy (DoubleHigherKind Int String))) `shouldBe` "DoubleHigherKind<number, string>"
diff --git a/test/LegalNameSpec.hs b/test/LegalNameSpec.hs
new file mode 100644
--- /dev/null
+++ b/test/LegalNameSpec.hs
@@ -0,0 +1,24 @@
+
+module LegalNameSpec where
+
+import Data.Aeson.TypeScript.LegalName
+import Data.List.NonEmpty (NonEmpty (..))
+import Test.Hspec
+
+tests :: Spec
+tests = describe "Data.Aeson.TypeScript.LegalName" $ do
+  describe "checkIllegalNameChars" $ do
+    describe "legal Haskell names" $ do
+      it "allows an uppercase letter" $ do
+        checkIllegalNameChars ('A' :| [])
+          `shouldBe` Nothing
+      it "allows an underscore" $ do
+        checkIllegalNameChars ('_' :| "asdf")
+          `shouldBe` Nothing
+      it "reports that ' is illegal" $ do
+        checkIllegalNameChars ('F' :| "oo'")
+          `shouldBe` Just ('\'' :| [])
+    describe "illegal Haskell names" $ do
+      it "allows a $" $ do
+        checkIllegalNameChars ('$' :| "asdf")
+          `shouldBe` Nothing
diff --git a/test/NoOmitNothingFields.hs b/test/NoOmitNothingFields.hs
--- a/test/NoOmitNothingFields.hs
+++ b/test/NoOmitNothingFields.hs
@@ -1,15 +1,3 @@
-{-# LANGUAGE CPP #-}
-{-# LANGUAGE ConstraintKinds #-}
-{-# LANGUAGE FlexibleContexts #-}
-{-# LANGUAGE KindSignatures #-}
-{-# LANGUAGE MonoLocalBinds #-}
-{-# LANGUAGE NamedFieldPuns #-}
-{-# LANGUAGE OverloadedStrings #-}
-{-# LANGUAGE QuasiQuotes #-}
-{-# LANGUAGE RecordWildCards #-}
-{-# LANGUAGE ScopedTypeVariables #-}
-{-# LANGUAGE TemplateHaskell #-}
-{-# OPTIONS_GHC -fno-warn-orphans #-}
 
 module NoOmitNothingFields (allTests) where
 
@@ -27,17 +15,7 @@
   it "encodes as expected" $ do
     let decls = getTypeScriptDeclarations (Proxy :: Proxy Optional)
 
-    decls `shouldBe` [TSTypeAlternatives {
-                         typeName = "Optional"
-                         , typeGenericVariables = []
-                         , alternativeTypes = ["IOptional"]
-                         }
-                     , TSInterfaceDeclaration {
-                         interfaceName = "IOptional"
-                         , interfaceGenericVariables = []
-                         , interfaceMembers = [TSField {fieldOptional = False
-                                                       , fieldName = "optionalInt"
-                                                       , fieldType = "number | null"}]
-                         }]
+    decls `shouldBe` [TSTypeAlternatives "Optional" [] ["IOptional"] Nothing
+                     , TSInterfaceDeclaration "IOptional" [] [TSField False "optionalInt" "number | null" Nothing] Nothing]
 
   tests
diff --git a/test/ObjectWithSingleFieldNoTagSingleConstructors.hs b/test/ObjectWithSingleFieldNoTagSingleConstructors.hs
--- a/test/ObjectWithSingleFieldNoTagSingleConstructors.hs
+++ b/test/ObjectWithSingleFieldNoTagSingleConstructors.hs
@@ -1,15 +1,3 @@
-{-# LANGUAGE CPP #-}
-{-# LANGUAGE QuasiQuotes #-}
-{-# LANGUAGE OverloadedStrings #-}
-{-# LANGUAGE TemplateHaskell #-}
-{-# LANGUAGE RecordWildCards #-}
-{-# LANGUAGE ScopedTypeVariables #-}
-{-# LANGUAGE NamedFieldPuns #-}
-{-# LANGUAGE KindSignatures #-}
-{-# LANGUAGE FlexibleContexts #-}
-{-# LANGUAGE ConstraintKinds #-}
-{-# LANGUAGE MonoLocalBinds #-}
-{-# OPTIONS_GHC -fno-warn-orphans #-}
 
 module ObjectWithSingleFieldNoTagSingleConstructors (main, tests) where
 
diff --git a/test/ObjectWithSingleFieldTagSingleConstructors.hs b/test/ObjectWithSingleFieldTagSingleConstructors.hs
--- a/test/ObjectWithSingleFieldTagSingleConstructors.hs
+++ b/test/ObjectWithSingleFieldTagSingleConstructors.hs
@@ -1,15 +1,3 @@
-{-# LANGUAGE CPP #-}
-{-# LANGUAGE QuasiQuotes #-}
-{-# LANGUAGE OverloadedStrings #-}
-{-# LANGUAGE TemplateHaskell #-}
-{-# LANGUAGE RecordWildCards #-}
-{-# LANGUAGE ScopedTypeVariables #-}
-{-# LANGUAGE NamedFieldPuns #-}
-{-# LANGUAGE KindSignatures #-}
-{-# LANGUAGE FlexibleContexts #-}
-{-# LANGUAGE ConstraintKinds #-}
-{-# LANGUAGE MonoLocalBinds #-}
-{-# OPTIONS_GHC -fno-warn-orphans #-}
 
 module ObjectWithSingleFieldTagSingleConstructors (main, tests) where
 
diff --git a/test/OmitNothingFields.hs b/test/OmitNothingFields.hs
--- a/test/OmitNothingFields.hs
+++ b/test/OmitNothingFields.hs
@@ -1,15 +1,3 @@
-{-# LANGUAGE CPP #-}
-{-# LANGUAGE QuasiQuotes #-}
-{-# LANGUAGE OverloadedStrings #-}
-{-# LANGUAGE TemplateHaskell #-}
-{-# LANGUAGE RecordWildCards #-}
-{-# LANGUAGE ScopedTypeVariables #-}
-{-# LANGUAGE NamedFieldPuns #-}
-{-# LANGUAGE KindSignatures #-}
-{-# LANGUAGE FlexibleContexts #-}
-{-# LANGUAGE ConstraintKinds #-}
-{-# LANGUAGE MonoLocalBinds #-}
-{-# OPTIONS_GHC -fno-warn-orphans #-}
 
 module OmitNothingFields (main, tests) where
 
@@ -31,10 +19,9 @@
                          interfaceName = "Optional"
                          , interfaceGenericVariables = []
                          , interfaceMembers = [
-                             TSField {fieldOptional = True
-                                     , fieldName = "optionalInt"
-                                     , fieldType = "number"}
+                             TSField True "optionalInt" "number" Nothing
                              ]
+                         , interfaceDoc = Nothing
                          }]
 
   tests
diff --git a/test/OpenTypeFamilies.hs b/test/OpenTypeFamilies.hs
--- a/test/OpenTypeFamilies.hs
+++ b/test/OpenTypeFamilies.hs
@@ -1,18 +1,5 @@
-{-# LANGUAGE QuasiQuotes #-}
-{-# LANGUAGE OverloadedStrings #-}
-{-# LANGUAGE TemplateHaskell #-}
-{-# LANGUAGE RecordWildCards #-}
-{-# LANGUAGE ScopedTypeVariables #-}
-{-# LANGUAGE NamedFieldPuns #-}
-{-# LANGUAGE KindSignatures #-}
-{-# LANGUAGE ConstraintKinds #-}
-{-# LANGUAGE DataKinds #-}
-{-# LANGUAGE GADTs #-}
-{-# LANGUAGE TypeFamilies #-}
 {-# LANGUAGE TypeFamilyDependencies #-}
-{-# LANGUAGE FlexibleContexts #-}
 {-# LANGUAGE UndecidableInstances #-}
-{-# OPTIONS_GHC -fno-warn-unused-top-binds #-}
 
 module OpenTypeFamilies (tests) where
 
@@ -53,38 +40,38 @@
     it [i|makes the declaration and types correctly|] $ do
       (getTypeScriptDeclarationsRecursively (Proxy :: Proxy (Simple T))) `shouldBe` ([
         TSInterfaceDeclaration "DeployEnvironment2" [] [
-          TSField False "\"single_node_env\"" "\"single\""
-          , TSField False "\"k8s_env\"" "\"k8s\""
-          , TSField False "T" "void"
-          ]
-        , TSTypeAlternatives "ISimple" ["T extends keyof DeployEnvironment2"] ["DeployEnvironment2[T]"]
-        , TSTypeAlternatives "Simple" ["T extends keyof DeployEnvironment2"] ["ISimple<T>"]
+          TSField False "\"single_node_env\"" "\"single\"" Nothing
+          , TSField False "\"k8s_env\"" "\"k8s\"" Nothing
+          , TSField False "T" "void" Nothing
+          ] Nothing
+        , TSTypeAlternatives "ISimple" ["T extends keyof DeployEnvironment2"] ["DeployEnvironment2[T]"] Nothing
+        , TSTypeAlternatives "Simple" ["T extends keyof DeployEnvironment2"] ["ISimple<T>"] Nothing
         ])
 
   describe "Complicated Beam-like user type" $ do
     it [i|makes the declaration and types correctly|] $ do
       (getTypeScriptDeclarations (Proxy :: Proxy (UserT T Identity))) `shouldBe` ([
-        TSTypeAlternatives "UserT" ["T extends keyof DeployEnvironment"] ["IUser<T>"]
+        TSTypeAlternatives "UserT" ["T extends keyof DeployEnvironment"] ["IUser<T>"] Nothing
         , TSInterfaceDeclaration "IUser" ["T extends keyof DeployEnvironment"] [
-            TSField False "_userUsername" "string"
-            , TSField False "_userCreatedAt" "number"
-            , TSField False "_userDeployEnvironment" "DeployEnvironment[T]"
-            ]
+            TSField False "_userUsername" "string" Nothing
+            , TSField False "_userCreatedAt" "number" Nothing
+            , TSField False "_userDeployEnvironment" "DeployEnvironment[T]" Nothing
+            ] Nothing
         ])
 
     it [i|get the declarations recursively|] $ do
       (getTypeScriptDeclarationsRecursively (Proxy :: Proxy (UserT T Identity))) `shouldBe` ([
         TSInterfaceDeclaration "DeployEnvironment" [] [
-          TSField False "\"single_node_env\"" "\"single\""
-          , TSField False "\"k8s_env\"" "\"k8s\""
-          , TSField False "T" "void"
-          ]
+          TSField False "\"single_node_env\"" "\"single\"" Nothing
+          , TSField False "\"k8s_env\"" "\"k8s\"" Nothing
+          , TSField False "T" "void" Nothing
+          ] Nothing
         , TSInterfaceDeclaration "IUser" ["T extends keyof DeployEnvironment"] [
-            TSField False "_userUsername" "string"
-            , TSField False "_userCreatedAt" "number"
-            , TSField False "_userDeployEnvironment" "DeployEnvironment[T]"
-            ]
-        , TSTypeAlternatives "UserT" ["T extends keyof DeployEnvironment"] ["IUser<T>"]
+            TSField False "_userUsername" "string" Nothing
+            , TSField False "_userCreatedAt" "number" Nothing
+            , TSField False "_userDeployEnvironment" "DeployEnvironment[T]" Nothing
+            ] Nothing
+        , TSTypeAlternatives "UserT" ["T extends keyof DeployEnvironment"] ["IUser<T>"] Nothing
         ])
 
 main :: IO ()
diff --git a/test/Spec.hs b/test/Spec.hs
--- a/test/Spec.hs
+++ b/test/Spec.hs
@@ -1,41 +1,50 @@
+{-# LANGUAGE CPP #-}
 
 module Main where
 
 import Test.Hspec
 
+import qualified Basic
 import qualified Formatting
 import qualified Generic
+import qualified GetDoc
 import qualified HigherKind
 import qualified ClosedTypeFamilies
 
+import qualified LegalNameSpec
+import qualified NoOmitNothingFields
 import qualified ObjectWithSingleFieldNoTagSingleConstructors
 import qualified ObjectWithSingleFieldTagSingleConstructors
+import qualified OmitNothingFields
 import qualified TaggedObjectNoTagSingleConstructors
 import qualified TaggedObjectTagSingleConstructors
 import qualified TwoElemArrayNoTagSingleConstructors
 import qualified TwoElemArrayTagSingleConstructors
 import qualified UntaggedNoTagSingleConstructors
 import qualified UntaggedTagSingleConstructors
-import qualified OmitNothingFields
-import qualified NoOmitNothingFields
 import qualified UnwrapUnaryRecords
 
 
 main :: IO ()
-main = hspec $ do
+main = hspec $ parallel $ do
+  Basic.tests
+  ClosedTypeFamilies.tests
   Formatting.tests
   Generic.tests
+#if MIN_VERSION_template_haskell(2,18,0)
+  GetDoc.tests
+#endif
   HigherKind.tests
-  ClosedTypeFamilies.tests
 
-  ObjectWithSingleFieldTagSingleConstructors.tests
+  LegalNameSpec.tests
+  NoOmitNothingFields.allTests
   ObjectWithSingleFieldNoTagSingleConstructors.tests
-  TaggedObjectTagSingleConstructors.tests
+  ObjectWithSingleFieldTagSingleConstructors.tests
+  OmitNothingFields.tests
   TaggedObjectNoTagSingleConstructors.tests
-  TwoElemArrayTagSingleConstructors.tests
+  TaggedObjectTagSingleConstructors.tests
   TwoElemArrayNoTagSingleConstructors.tests
-  UntaggedTagSingleConstructors.tests
+  TwoElemArrayTagSingleConstructors.tests
   UntaggedNoTagSingleConstructors.tests
-  OmitNothingFields.tests
-  NoOmitNothingFields.allTests
+  UntaggedTagSingleConstructors.tests
   UnwrapUnaryRecords.allTests
diff --git a/test/TaggedObjectNoTagSingleConstructors.hs b/test/TaggedObjectNoTagSingleConstructors.hs
--- a/test/TaggedObjectNoTagSingleConstructors.hs
+++ b/test/TaggedObjectNoTagSingleConstructors.hs
@@ -1,15 +1,3 @@
-{-# LANGUAGE CPP #-}
-{-# LANGUAGE QuasiQuotes #-}
-{-# LANGUAGE OverloadedStrings #-}
-{-# LANGUAGE TemplateHaskell #-}
-{-# LANGUAGE RecordWildCards #-}
-{-# LANGUAGE ScopedTypeVariables #-}
-{-# LANGUAGE NamedFieldPuns #-}
-{-# LANGUAGE KindSignatures #-}
-{-# LANGUAGE FlexibleContexts #-}
-{-# LANGUAGE ConstraintKinds #-}
-{-# LANGUAGE MonoLocalBinds #-}
-{-# OPTIONS_GHC -fno-warn-orphans #-}
 
 module TaggedObjectNoTagSingleConstructors (main, tests) where
 
diff --git a/test/TaggedObjectTagSingleConstructors.hs b/test/TaggedObjectTagSingleConstructors.hs
--- a/test/TaggedObjectTagSingleConstructors.hs
+++ b/test/TaggedObjectTagSingleConstructors.hs
@@ -1,15 +1,3 @@
-{-# LANGUAGE CPP #-}
-{-# LANGUAGE QuasiQuotes #-}
-{-# LANGUAGE OverloadedStrings #-}
-{-# LANGUAGE TemplateHaskell #-}
-{-# LANGUAGE RecordWildCards #-}
-{-# LANGUAGE ScopedTypeVariables #-}
-{-# LANGUAGE NamedFieldPuns #-}
-{-# LANGUAGE KindSignatures #-}
-{-# LANGUAGE FlexibleContexts #-}
-{-# LANGUAGE ConstraintKinds #-}
-{-# LANGUAGE MonoLocalBinds #-}
-{-# OPTIONS_GHC -fno-warn-orphans #-}
 
 module TaggedObjectTagSingleConstructors (main, tests) where
 
diff --git a/test/TestBoilerplate.hs b/test/TestBoilerplate.hs
--- a/test/TestBoilerplate.hs
+++ b/test/TestBoilerplate.hs
@@ -1,16 +1,4 @@
-{-# LANGUAGE CPP #-}
-{-# LANGUAGE QuasiQuotes #-}
-{-# LANGUAGE OverloadedStrings #-}
-{-# LANGUAGE TemplateHaskell #-}
-{-# LANGUAGE RecordWildCards #-}
-{-# LANGUAGE ScopedTypeVariables #-}
-{-# LANGUAGE NamedFieldPuns #-}
-{-# LANGUAGE KindSignatures #-}
-{-# LANGUAGE FlexibleContexts #-}
-{-# LANGUAGE ConstraintKinds #-}
-{-# LANGUAGE TypeFamilies #-}
 {-# LANGUAGE UndecidableInstances #-}
-{-# OPTIONS_GHC -fno-warn-orphans #-}
 
 module TestBoilerplate where
 
diff --git a/test/TwoElemArrayNoTagSingleConstructors.hs b/test/TwoElemArrayNoTagSingleConstructors.hs
--- a/test/TwoElemArrayNoTagSingleConstructors.hs
+++ b/test/TwoElemArrayNoTagSingleConstructors.hs
@@ -1,15 +1,3 @@
-{-# LANGUAGE CPP #-}
-{-# LANGUAGE QuasiQuotes #-}
-{-# LANGUAGE OverloadedStrings #-}
-{-# LANGUAGE TemplateHaskell #-}
-{-# LANGUAGE RecordWildCards #-}
-{-# LANGUAGE ScopedTypeVariables #-}
-{-# LANGUAGE NamedFieldPuns #-}
-{-# LANGUAGE KindSignatures #-}
-{-# LANGUAGE FlexibleContexts #-}
-{-# LANGUAGE ConstraintKinds #-}
-{-# LANGUAGE MonoLocalBinds #-}
-{-# OPTIONS_GHC -fno-warn-orphans #-}
 
 module TwoElemArrayNoTagSingleConstructors (main, tests) where
 
diff --git a/test/TwoElemArrayTagSingleConstructors.hs b/test/TwoElemArrayTagSingleConstructors.hs
--- a/test/TwoElemArrayTagSingleConstructors.hs
+++ b/test/TwoElemArrayTagSingleConstructors.hs
@@ -1,15 +1,3 @@
-{-# LANGUAGE CPP #-}
-{-# LANGUAGE QuasiQuotes #-}
-{-# LANGUAGE OverloadedStrings #-}
-{-# LANGUAGE TemplateHaskell #-}
-{-# LANGUAGE RecordWildCards #-}
-{-# LANGUAGE ScopedTypeVariables #-}
-{-# LANGUAGE NamedFieldPuns #-}
-{-# LANGUAGE KindSignatures #-}
-{-# LANGUAGE FlexibleContexts #-}
-{-# LANGUAGE ConstraintKinds #-}
-{-# LANGUAGE MonoLocalBinds #-}
-{-# OPTIONS_GHC -fno-warn-orphans #-}
 
 module TwoElemArrayTagSingleConstructors (main, tests) where
 
diff --git a/test/UntaggedNoTagSingleConstructors.hs b/test/UntaggedNoTagSingleConstructors.hs
--- a/test/UntaggedNoTagSingleConstructors.hs
+++ b/test/UntaggedNoTagSingleConstructors.hs
@@ -1,15 +1,4 @@
 {-# LANGUAGE CPP #-}
-{-# LANGUAGE QuasiQuotes #-}
-{-# LANGUAGE OverloadedStrings #-}
-{-# LANGUAGE TemplateHaskell #-}
-{-# LANGUAGE RecordWildCards #-}
-{-# LANGUAGE ScopedTypeVariables #-}
-{-# LANGUAGE NamedFieldPuns #-}
-{-# LANGUAGE KindSignatures #-}
-{-# LANGUAGE FlexibleContexts #-}
-{-# LANGUAGE ConstraintKinds #-}
-{-# LANGUAGE MonoLocalBinds #-}
-{-# OPTIONS_GHC -fno-warn-orphans #-}
 
 module UntaggedNoTagSingleConstructors (main, tests) where
 
diff --git a/test/UntaggedTagSingleConstructors.hs b/test/UntaggedTagSingleConstructors.hs
--- a/test/UntaggedTagSingleConstructors.hs
+++ b/test/UntaggedTagSingleConstructors.hs
@@ -1,15 +1,4 @@
 {-# LANGUAGE CPP #-}
-{-# LANGUAGE QuasiQuotes #-}
-{-# LANGUAGE OverloadedStrings #-}
-{-# LANGUAGE TemplateHaskell #-}
-{-# LANGUAGE RecordWildCards #-}
-{-# LANGUAGE ScopedTypeVariables #-}
-{-# LANGUAGE NamedFieldPuns #-}
-{-# LANGUAGE KindSignatures #-}
-{-# LANGUAGE FlexibleContexts #-}
-{-# LANGUAGE ConstraintKinds #-}
-{-# LANGUAGE MonoLocalBinds #-}
-{-# OPTIONS_GHC -fno-warn-orphans #-}
 
 module UntaggedTagSingleConstructors (main, tests) where
 
diff --git a/test/UnwrapUnaryRecords.hs b/test/UnwrapUnaryRecords.hs
--- a/test/UnwrapUnaryRecords.hs
+++ b/test/UnwrapUnaryRecords.hs
@@ -1,15 +1,4 @@
 {-# LANGUAGE CPP #-}
-{-# LANGUAGE QuasiQuotes #-}
-{-# LANGUAGE OverloadedStrings #-}
-{-# LANGUAGE TemplateHaskell #-}
-{-# LANGUAGE RecordWildCards #-}
-{-# LANGUAGE ScopedTypeVariables #-}
-{-# LANGUAGE NamedFieldPuns #-}
-{-# LANGUAGE KindSignatures #-}
-{-# LANGUAGE FlexibleContexts #-}
-{-# LANGUAGE ConstraintKinds #-}
-{-# LANGUAGE MonoLocalBinds #-}
-{-# OPTIONS_GHC -fno-warn-orphans #-}
 
 module UnwrapUnaryRecords (allTests) where
 
@@ -30,8 +19,8 @@
     let decls = getTypeScriptDeclarations (Proxy :: Proxy OneField)
 
     decls `shouldBe` [
-      TSTypeAlternatives {typeName = "OneField", typeGenericVariables = [], alternativeTypes = ["IOneField"]}
-      ,TSTypeAlternatives {typeName = "IOneField", typeGenericVariables = [], alternativeTypes = ["string"]}
+      TSTypeAlternatives "OneField" [] ["IOneField"] Nothing
+      ,TSTypeAlternatives "IOneField" [] ["string"] Nothing
       ]
 
   tests
@@ -42,5 +31,5 @@
 allTests = tests
 #endif
 
--- main :: IO ()
--- main = hspec allTests
+main :: IO ()
+main = hspec allTests
diff --git a/test/Util.hs b/test/Util.hs
--- a/test/Util.hs
+++ b/test/Util.hs
@@ -1,4 +1,4 @@
-{-# LANGUAGE CPP, QuasiQuotes, OverloadedStrings, TemplateHaskell, RecordWildCards, ScopedTypeVariables, NamedFieldPuns, LambdaCase #-}
+{-# LANGUAGE CPP #-}
 
 module Util where
 
@@ -14,7 +14,8 @@
 import System.Exit
 import System.FilePath
 import System.IO.Temp
-import System.Process
+import System.Process hiding (cwd)
+
 
 npmInstallScript, yarnInstallScript, localTSC :: String
 npmInstallScript = "test/assets/npm_install.sh"
diff --git a/test/Util/Aeson.hs b/test/Util/Aeson.hs
--- a/test/Util/Aeson.hs
+++ b/test/Util/Aeson.hs
@@ -3,8 +3,10 @@
 module Util.Aeson where
 
 #if MIN_VERSION_aeson(2,0,0)
+import qualified Data.Aeson.Key as K
 import qualified Data.Aeson.KeyMap as KM
 
+aesonFromList :: [(K.Key, v)] -> KM.KeyMap v
 aesonFromList = KM.fromList
 #else
 import Data.HashMap.Strict as HM
