Last active
January 13, 2023 16:27
-
-
Save JacobWeisenburger/36cc8fae5c40fca692cb59a60f3afa33 to your computer and use it in GitHub Desktop.
an easier way to make error maps for Zod
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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