diff --git a/src/Data/Aeson/TypeScript/TH.hs b/src/Data/Aeson/TypeScript/TH.hs index 3cd7227..3ce3491 100644 --- a/src/Data/Aeson/TypeScript/TH.hs +++ b/src/Data/Aeson/TypeScript/TH.hs @@ -308,10 +308,19 @@ handleConstructor (ExtraTypeScriptOptions {..}) options (DatatypeInfo {..}) gene interfaceName = "I" <> (lastNameComponent' $ constructorName ci) tupleEncoding = do - let typ = contentsTupleTypeSubstituted genericVariables ci - stringExp <- lift $ case typ of - (AppT (ConT name) t) | name == ''Maybe -> [|$(getTypeAsStringExp t) <> " | null"|] - _ -> getTypeAsStringExp typ + let fields = constructorFields ci + stringExp <- lift $ case fields of + [] -> [|"void[]"|] + [x] -> case mapType genericVariables x of + (AppT (ConT name) t) | name == ''Maybe -> [|$(getTypeAsStringExp t) <> " | null"|] + mappedType -> getTypeAsStringExp mappedType + xs -> do + -- Process each field individually to handle Maybe types + fieldStrings <- forM (fmap (mapType genericVariables) xs) $ \fieldType -> case fieldType of + (AppT (ConT name) t) | name == ''Maybe -> [|$(getTypeAsStringExp t) <> " | null"|] + _ -> getTypeAsStringExp fieldType + let fieldExps = map return fieldStrings + [|"[" <> $(foldr1 (\a b -> [|$a <> ", " <> $b|]) fieldExps) <> "]"|] lift [|TSTypeAlternatives $(TH.stringE interfaceName) $(genericVariablesListExpr True genericVariables) diff --git a/test/Basic.hs b/test/Basic.hs index a6c7a86..72a72c2 100644 --- a/test/Basic.hs +++ b/test/Basic.hs @@ -4,6 +4,7 @@ module Basic (tests) where import Data.Aeson as A import Data.Aeson.TypeScript.TH import Data.Aeson.TypeScript.Types +import Data.List.NonEmpty (NonEmpty) import Data.Proxy import Data.String.Interpolate import Prelude hiding (Double) @@ -20,6 +21,24 @@ $(deriveTypeScript (A.defaultOptions { A.tagSingleConstructors = True data Test1 = Test1 (Maybe Int) deriveTypeScript A.defaultOptions ''Test1 +data Test2 = Test2 String [Int] (Maybe String) +deriveTypeScript A.defaultOptions ''Test2 + +-- Test case for Maybe types in multi-field tuples +data PromptKey = PromptKey String deriving (Eq, Show) + +$(deriveTypeScript A.defaultOptions ''PromptKey) + +newtype ExtraInputPrompt = ExtraInputPrompt String deriving (Eq, Show) + +$(deriveTypeScript A.defaultOptions ''ExtraInputPrompt) + +data WidgetActionPayload + = InfoRequest String [PromptKey] (Maybe (NonEmpty ExtraInputPrompt)) + deriving (Eq, Show) + +$(deriveTypeScript A.defaultOptions ''WidgetActionPayload) + tests :: SpecWith () tests = describe "Basic tests" $ do describe "tagSingleConstructors and constructorTagModifier" $ do @@ -40,6 +59,18 @@ tests = describe "Basic tests" $ do , TSTypeAlternatives "ITest1" [] ["number | null"] Nothing ]) + it [i|Maybe in multi-field tuple includes null option|] $ do + (getTypeScriptDeclarations (Proxy :: Proxy Test2)) `shouldBe` ([ + TSTypeAlternatives "Test2" [] ["ITest2"] Nothing + , TSTypeAlternatives "ITest2" [] ["[string, number[], string | null]"] Nothing + ]) + + it [i|WidgetActionPayload tuple includes null for Maybe list|] $ do + (getTypeScriptDeclarations (Proxy :: Proxy WidgetActionPayload)) + `shouldBe` ( [ TSTypeAlternatives "WidgetActionPayload" [] ["IInfoRequest"] Nothing, + TSTypeAlternatives "IInfoRequest" [] ["[string, PromptKey[], ExtraInputPrompt[] | null]"] Nothing + ] + ) main :: IO () main = hspec tests