Skip to content

Instantly share code, notes, and snippets.

@JacobWeisenburger
Last active January 13, 2023 16:27
Show Gist options
  • Save JacobWeisenburger/36cc8fae5c40fca692cb59a60f3afa33 to your computer and use it in GitHub Desktop.
Save JacobWeisenburger/36cc8fae5c40fca692cb59a60f3afa33 to your computer and use it in GitHub Desktop.
an easier way to make error maps for Zod
import { z } from 'zod'
type ErrorCode = z.ZodIssueCode | 'required'
type Message = string
type MessageBuilder = ( data: unknown, options?: any[] ) => Message
type ErrorRecord = Partial<Record<ErrorCode, Message | MessageBuilder>>
function makeErrorMap ( errorRecord: ErrorRecord ): z.ZodErrorMap {
return ( issue, ctx ) => {
const options = issue.code === 'invalid_enum_value'
? issue.options : undefined
const errorCode: ErrorCode =
issue.code === 'invalid_type' && ctx.data === undefined
? 'required' : issue.code
const messageOrBuilder = errorRecord[ errorCode ]
const message = typeof messageOrBuilder === 'function'
? messageOrBuilder( ctx.data, options ) : messageOrBuilder
return message ? { message } : { message: ctx.defaultError }
}
}
const errorMap = makeErrorMap( {
required: 'Custom required message',
invalid_type: data => `${ JSON.stringify( data ) } is not a valid type`,
invalid_enum_value: ( data, options ) =>
`${ JSON.stringify( data ) } is not a valid enum value. Valid options: ${ options?.join( ' | ' ) }`,
invalid_date: data => {
const value = data instanceof Date ? data.valueOf() : JSON.stringify( data )
return `${ value } is not a valid date`
},
} )
function dataOrError ( result: z.SafeParseReturnType<unknown, unknown> ) {
return result.success ? result.data : result.error.issues[ 0 ].message
}
{
console.group( 'z.string' )
const schema = z.string( { errorMap } )
console.log( dataOrError( schema.safeParse( 'foo' ) ) )
console.log( dataOrError( schema.safeParse( undefined ) ) )
console.log( dataOrError( schema.safeParse( 42 ) ) )
console.log( dataOrError( schema.safeParse( [ 42 ] ) ) )
console.groupEnd()
console.log()
}
{
console.group( 'z.number' )
const schema = z.number( { errorMap } )
console.log( dataOrError( schema.safeParse( 42 ) ) )
console.log( dataOrError( schema.safeParse( undefined ) ) )
console.log( dataOrError( schema.safeParse( 'foo' ) ) )
console.log( dataOrError( schema.safeParse( { foo: 'foo' } ) ) )
console.groupEnd()
console.log()
}
{
console.group( 'z.enum' )
const schema = z.enum( [ 'public', 'unlisted', 'private' ], { errorMap } )
console.log( dataOrError( schema.safeParse( 'unlisted' ) ) )
console.log( dataOrError( schema.safeParse( undefined ) ) )
console.log( dataOrError( schema.safeParse( null ) ) )
console.log( dataOrError( schema.safeParse( 'foo' ) ) )
console.groupEnd()
console.log()
}
{
console.group( 'z.date' )
const schema = z.date( { errorMap } )
console.log( dataOrError( schema.safeParse( new Date ) ) )
console.log( dataOrError( schema.safeParse( undefined ) ) )
console.log( dataOrError( schema.safeParse( '2023-01-13' ) ) )
console.log( dataOrError( schema.safeParse( null ) ) )
console.log( dataOrError( schema.safeParse( new Date( '' ) ) ) )
console.groupEnd()
console.log()
}
/*
logs:
z.string
foo
Custom required message
42 is not a valid type
[42] is not a valid type
z.number
42
Custom required message
"foo" is not a valid type
{"foo":"foo"} is not a valid type
z.enum
unlisted
Custom required message
null is not a valid type
"foo" is not a valid enum value. Valid options: public | unlisted | private
z.date
2023-01-13T15:41:37.771Z
Custom required message
"2023-01-13" is not a valid type
null is not a valid type
NaN is not a valid date
*/
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment