I'm using joi and @types/joi with TypeScript. Joi has an extend method which allows extending joi by returning a new instance without modifying original joi library. I created an extended instance with it.
To create definition for this extended instance, I tried Module Augmentation
as described here using code below:
declare module 'joi' {
// Add a new Schema type which has noChildren() method.
interface CustomSchema extends ObjectSchema {
noChildren(): this;
}
}
However, as expected, this modifies original definition by augmenting it. What I want is to create definitions for the extended instance which inherits everything from original without modifying it.
Also extended Joi
is created as below:
import * as Joi from 'joi';
const JoiExtended = Joi.extend({...some implementation...})
// How to export?
// export * from 'Joi' ---> In this case, original non-extended Joi is exported
// export default JoiExtended ---> Imported `Joi` reports: Cannot find namespace 'Joi'
Joi
?P.S. I'm learning TypeScript and searched for an answer for this question but couldn't find an answer, maybe, because I'm not accustomed to typescript terminology and search for wrong terms.
TypeScript supports the following 4 Modules: commonjs, amd, system and umd.
A module can be created using the keyword export and a module can be used in another module using the keyword import . In TypeScript, files containing a top-level export or import are considered modules. For example, we can make the above files as modules as below. console.
Joi.extend
returns a new instance of the joi
module for which you can use the exported Root
type.
You'll need to create an interface that extends Joi.Root
and another that extends the base joi
type that you're extending. You can simply export your custom joi
instance like you would any other object.
Below is an example using the round()
and dividable()
rules from the API Documentation examples on extend()
.
import * as Joi from 'joi';
interface ExtendedNumberSchema extends Joi.NumberSchema {
round(): this;
dividable(num: number): this;
}
interface ExtendedJoi extends Joi.Root {
number(): ExtendedNumberSchema;
}
const customJoi: ExtendedJoi = Joi.extend((joi) => ({
base: joi.number(),
name: 'number',
language: {
round: 'needs to be a rounded number', // Used below as 'number.round'
dividable: 'needs to be dividable by {{q}}'
},
pre(value, state, options) {
if (options.convert && this._flags.round) {
return Math.round(value); // Change the value
}
return value; // Keep the value as it was
},
rules: [
{
name: 'round',
setup(params) {
this._flags.round = true; // Set a flag for later use
},
validate(params, value, state, options) {
if (value % 1 !== 0) {
// Generate an error, state and options need to be passed
return this.createError('number.round', {v: value}, state, options);
}
return value; // Everything is OK
}
},
{
name: 'dividable',
params: {
q: joi.alternatives([joi.number().required(), joi.func().ref()])
},
validate(params, value, state, options) {
if (value % params.q !== 0) {
// Generate an error, state and options need to be passed, q is used in the language
return this.createError('number.dividable', {v: value, q: params.q}, state, options);
}
return value; // Everything is OK
}
}
]
}));
const schema = {
a: customJoi.number().round().dividable(3)
};
const result = customJoi.validate({a: 4.1}, schema); // will fail because 4 is no divisible by 3
console.log(result);
export = customJoi;
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With