I'm using zod
which allows to define some validation rules using fluent function.
Especially, one of the functionis optional
which allows to declare a field as optional. Unfortunately, this function does not accept a flag to enable/disable the optional behavior. In my case, the form is built dynamically and the optional flag must be defined at run time.
I can create a small utility method to add this logic :
import { z, ZodType} from 'zod';
const fieldIsRequired = true;
// Method 1 : wrapper / Working
const makeOptional = (input : ZodType, required : boolean): ZodType => required ? input : input.optional();
const entry1 = makeOptional(
z
.string()
.min(10)
.max(100)
, !fieldIsRequired
);
This is working well, but I lost the fluent code. Having one rule is acceptable, but adding more rules will leads to a hamburger of function call and parameters
How can I add a new fluent function to the zod type, which come from a 3rd party lib ?
I've tried to implement extension methods, but I failed finding the correct syntax.
Here's what I tried :
import { z, ZodType} from 'zod';
const fieldIsRequired = true;
// Method 2 : extension method / Not Working
declare namespace zod {
export abstract class ZodType {
makeOptional: (required: boolean)=> ZodType;
}
}
// Add syntaxic sugar to the Zod schema
ZodType.prototype.makeOptional = function (required: boolean): ZodType {
return required ? this : this.optional();
};
const entry2 =
z
.string()
.min(10)
.max(100)
.makeOptional(!fieldIsRequired);
How to fix this ?
Repro : TS playground
You were very close. I think you needed declare module
not declare namespace
. This works for me:
import { z, ZodType } from 'zod';
const fieldIsRequired = true;
declare module 'zod' {
export interface ZodType {
makeOptional: (required: boolean)=> ZodType;
}
}
// Add syntaxic sugar to the Zod schema
z.ZodType.prototype.makeOptional = function (required: boolean): ZodType {
return required ? this : this.optional();
};
const entry2 =
z
.string()
.min(10)
.max(100)
.makeOptional(!fieldIsRequired);
I figured this out by looking at the Module Augmentation section of the typescript docs. I almost made a post saying it wasn't possible since the next section says something about merging classes, but then I noticed they were using declare module
.