@@ -485,6 +485,7 @@ export abstract class ZodType<
485485export type ZodStringCheck =
486486 | { kind : "min" ; value : number ; message ?: string }
487487 | { kind : "max" ; value : number ; message ?: string }
488+ | { kind : "length" ; value : number ; message ?: string }
488489 | { kind : "email" ; message ?: string }
489490 | { kind : "url" ; message ?: string }
490491 | { kind : "uuid" ; message ?: string }
@@ -589,6 +590,7 @@ export class ZodString extends ZodType<string, ZodStringDef> {
589590 minimum : check . value ,
590591 type : "string" ,
591592 inclusive : true ,
593+ exact : false ,
592594 message : check . message ,
593595 } ) ;
594596 status . dirty ( ) ;
@@ -601,10 +603,37 @@ export class ZodString extends ZodType<string, ZodStringDef> {
601603 maximum : check . value ,
602604 type : "string" ,
603605 inclusive : true ,
606+ exact : false ,
604607 message : check . message ,
605608 } ) ;
606609 status . dirty ( ) ;
607610 }
611+ } else if ( check . kind === "length" ) {
612+ const tooBig = input . data . length > check . value ;
613+ const tooSmall = input . data . length < check . value ;
614+ if ( tooBig || tooSmall ) {
615+ ctx = this . _getOrReturnCtx ( input , ctx ) ;
616+ if ( tooBig ) {
617+ addIssueToContext ( ctx , {
618+ code : ZodIssueCode . too_big ,
619+ maximum : check . value ,
620+ type : "string" ,
621+ inclusive : true ,
622+ exact : true ,
623+ message : check . message ,
624+ } ) ;
625+ } else if ( tooSmall ) {
626+ addIssueToContext ( ctx , {
627+ code : ZodIssueCode . too_small ,
628+ minimum : check . value ,
629+ type : "string" ,
630+ inclusive : true ,
631+ exact : true ,
632+ message : check . message ,
633+ } ) ;
634+ }
635+ status . dirty ( ) ;
636+ }
608637 } else if ( check . kind === "email" ) {
609638 if ( ! emailRegex . test ( input . data ) ) {
610639 ctx = this . _getOrReturnCtx ( input , ctx ) ;
@@ -798,7 +827,11 @@ export class ZodString extends ZodType<string, ZodStringDef> {
798827 }
799828
800829 length ( len : number , message ?: errorUtil . ErrMessage ) {
801- return this . min ( len , message ) . max ( len , message ) ;
830+ return this . _addCheck ( {
831+ kind : "length" ,
832+ value : len ,
833+ ...errorUtil . errToObj ( message ) ,
834+ } ) ;
802835 }
803836
804837 /**
@@ -932,6 +965,7 @@ export class ZodNumber extends ZodType<number, ZodNumberDef> {
932965 minimum : check . value ,
933966 type : "number" ,
934967 inclusive : check . inclusive ,
968+ exact : false ,
935969 message : check . message ,
936970 } ) ;
937971 status . dirty ( ) ;
@@ -947,6 +981,7 @@ export class ZodNumber extends ZodType<number, ZodNumberDef> {
947981 maximum : check . value ,
948982 type : "number" ,
949983 inclusive : check . inclusive ,
984+ exact : false ,
950985 message : check . message ,
951986 } ) ;
952987 status . dirty ( ) ;
@@ -1255,6 +1290,7 @@ export class ZodDate extends ZodType<Date, ZodDateDef> {
12551290 code : ZodIssueCode . too_small ,
12561291 message : check . message ,
12571292 inclusive : true ,
1293+ exact : false ,
12581294 minimum : check . value ,
12591295 type : "date" ,
12601296 } ) ;
@@ -1267,6 +1303,7 @@ export class ZodDate extends ZodType<Date, ZodDateDef> {
12671303 code : ZodIssueCode . too_big ,
12681304 message : check . message ,
12691305 inclusive : true ,
1306+ exact : false ,
12701307 maximum : check . value ,
12711308 type : "date" ,
12721309 } ) ;
@@ -1568,6 +1605,7 @@ export interface ZodArrayDef<T extends ZodTypeAny = ZodTypeAny>
15681605 extends ZodTypeDef {
15691606 type : T ;
15701607 typeName : ZodFirstPartyTypeKind . ZodArray ;
1608+ exactLength : { value : number ; message ?: string } | null ;
15711609 minLength : { value : number ; message ?: string } | null ;
15721610 maxLength : { value : number ; message ?: string } | null ;
15731611}
@@ -1604,13 +1642,31 @@ export class ZodArray<
16041642 return INVALID ;
16051643 }
16061644
1645+ if ( def . exactLength !== null ) {
1646+ const tooBig = ctx . data . length > def . exactLength . value ;
1647+ const tooSmall = ctx . data . length < def . exactLength . value ;
1648+ if ( tooBig || tooSmall ) {
1649+ addIssueToContext ( ctx , {
1650+ code : tooBig ? ZodIssueCode . too_big : ZodIssueCode . too_small ,
1651+ minimum : ( tooSmall ? def . exactLength . value : undefined ) as number ,
1652+ maximum : ( tooBig ? def . exactLength . value : undefined ) as number ,
1653+ type : "array" ,
1654+ inclusive : true ,
1655+ exact : true ,
1656+ message : def . exactLength . message ,
1657+ } ) ;
1658+ status . dirty ( ) ;
1659+ }
1660+ }
1661+
16071662 if ( def . minLength !== null ) {
16081663 if ( ctx . data . length < def . minLength . value ) {
16091664 addIssueToContext ( ctx , {
16101665 code : ZodIssueCode . too_small ,
16111666 minimum : def . minLength . value ,
16121667 type : "array" ,
16131668 inclusive : true ,
1669+ exact : false ,
16141670 message : def . minLength . message ,
16151671 } ) ;
16161672 status . dirty ( ) ;
@@ -1624,6 +1680,7 @@ export class ZodArray<
16241680 maximum : def . maxLength . value ,
16251681 type : "array" ,
16261682 inclusive : true ,
1683+ exact : false ,
16271684 message : def . maxLength . message ,
16281685 } ) ;
16291686 status . dirty ( ) ;
@@ -1670,7 +1727,10 @@ export class ZodArray<
16701727 }
16711728
16721729 length ( len : number , message ?: errorUtil . ErrMessage ) : this {
1673- return this . min ( len , message ) . max ( len , message ) as any ;
1730+ return new ZodArray ( {
1731+ ...this . _def ,
1732+ exactLength : { value : len , message : errorUtil . toString ( message ) } ,
1733+ } ) as any ;
16741734 }
16751735
16761736 nonempty ( message ?: errorUtil . ErrMessage ) : ZodArray < T , "atleastone" > {
@@ -1685,6 +1745,7 @@ export class ZodArray<
16851745 type : schema ,
16861746 minLength : null ,
16871747 maxLength : null ,
1748+ exactLength : null ,
16881749 typeName : ZodFirstPartyTypeKind . ZodArray ,
16891750 ...processCreateParams ( params ) ,
16901751 } ) ;
@@ -2747,6 +2808,7 @@ export class ZodTuple<
27472808 code : ZodIssueCode . too_small ,
27482809 minimum : this . _def . items . length ,
27492810 inclusive : true ,
2811+ exact : false ,
27502812 type : "array" ,
27512813 } ) ;
27522814
@@ -2760,6 +2822,7 @@ export class ZodTuple<
27602822 code : ZodIssueCode . too_big ,
27612823 maximum : this . _def . items . length ,
27622824 inclusive : true ,
2825+ exact : false ,
27632826 type : "array" ,
27642827 } ) ;
27652828 status . dirty ( ) ;
@@ -3060,6 +3123,7 @@ export class ZodSet<Value extends ZodTypeAny = ZodTypeAny> extends ZodType<
30603123 minimum : def . minSize . value ,
30613124 type : "set" ,
30623125 inclusive : true ,
3126+ exact : false ,
30633127 message : def . minSize . message ,
30643128 } ) ;
30653129 status . dirty ( ) ;
@@ -3073,6 +3137,7 @@ export class ZodSet<Value extends ZodTypeAny = ZodTypeAny> extends ZodType<
30733137 maximum : def . maxSize . value ,
30743138 type : "set" ,
30753139 inclusive : true ,
3140+ exact : false ,
30763141 message : def . maxSize . message ,
30773142 } ) ;
30783143 status . dirty ( ) ;
0 commit comments