@@ -76,11 +76,15 @@ const onObject: Producer = (
7676 ( [ key , value ] ) => {
7777 const { description : comment , deprecated : isDeprecated } =
7878 globalRegistry . get ( value ) || { } ;
79+ const isOptional =
80+ ( isResponse ? value . _zod . optout : value . _zod . optin ) === "optional" ;
81+ const hasUndefined =
82+ isOptional && ! ( value instanceof z . core . $ZodExactOptional ) ;
7983 return api . makeInterfaceProp ( key , next ( value ) , {
8084 comment,
8185 isDeprecated,
82- isOptional :
83- ( isResponse ? value . _zod . optout : value . _zod . optin ) === "optional" ,
86+ isOptional,
87+ hasUndefined ,
8488 } ) ;
8589 } ,
8690 ) ;
@@ -124,7 +128,16 @@ const onTuple: Producer = (
124128const onRecord : Producer = (
125129 { _zod : { def } } : z . core . $ZodRecord ,
126130 { next, api } ,
127- ) => api . ensureTypeNode ( "Record" , [ def . keyType , def . valueType ] . map ( next ) ) ;
131+ ) => {
132+ const [ keyNode , valueNode ] = [ def . keyType , def . valueType ] . map ( next ) ;
133+ const primary = api . ensureTypeNode ( "Record" , [ keyNode , valueNode ] ) ;
134+ const isLoose = def . mode === "loose" ;
135+ if ( ! isLoose ) return primary ;
136+ return api . f . createIntersectionTypeNode ( [
137+ primary ,
138+ api . ensureTypeNode ( "Record" , [ "PropertyKey" , valueNode ] ) ,
139+ ] ) ;
140+ } ;
128141
129142const intersect = R . tryCatch (
130143 ( api : TypescriptAPI , nodes : ts . TypeNode [ ] ) => {
@@ -170,7 +183,8 @@ const onWrapped: Producer = (
170183 | z . core . $ZodCatch
171184 | z . core . $ZodDefault
172185 | z . core . $ZodOptional
173- | z . core . $ZodNonOptional ,
186+ | z . core . $ZodNonOptional
187+ | z . core . $ZodExactOptional ,
174188 { next } ,
175189) => next ( def . innerType ) ;
176190
0 commit comments