Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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?

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.

like image 442
ozm Avatar asked Dec 03 '17 12:12

ozm


People also ask

Does TypeScript use Commonjs?

TypeScript supports the following 4 Modules: commonjs, amd, system and umd.

How to define module in TypeScript?

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.


1 Answers

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;
like image 189
Cuthbert Avatar answered Nov 15 '22 03:11

Cuthbert