简体   繁体   中英

How to extend a module from npm using TypeScript?

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'
  1. How can I create extended definitions?
  2. How to export extended Joi ?

PS 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.

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;

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM