Monday, August 31, 2015

module.exports has lesser mental model when exporting a module

On my post about sharing TypeScript classes between client-side and server-side. I used exports rather than module.exports. However, as I later learned, it's better to use module.exports as it's the one being directly returned by the require function, module.exports is the real deal. If we uses module.exports rather than exports, we don't need to do this anymore:

class ExternalizedDomain {
    static Person : typeof Domain.Person = require('./shared/Domain/Person').DomainPerson;
    static Country : typeof Domain.Country = require('./shared/Domain/Country').DomainCountry;
}

And also the drawback of the idiom above is it is not compatible with proxyquire:

it("applies interest using stubbed calculator", () => {

 var calculatorStub : any = {};

 var financialCalculator : typeof Domain.FinancialCalculator = 
                  proxyquire('../shared/Domain/FinancialCalculator', { './Calculator': calculatorStub });

 var interestApplied = financialCalculator.applyInterest(200, 0.2);
 expect(interestApplied).toEqual(240);


 calculatorStub.multiply = (a,b) => 6;
 var interestAppliedFromStubbedCalculator = financialCalculator.applyInterest(100, 0.2);
 expect(interestAppliedFromStubbedCalculator).toEqual(6);
});


There's no way in proxyquire to specificy an specific property (e.g., .DomainPerson) of the object assigned to module.exports. To make the external module compatible with proxyquire, do as the following:


class ExternalizedDomain {
    static Person : typeof Domain.Person = require('./shared/Domain/Person');
    static Country : typeof Domain.Country = require('./shared/Domain/Country');
}


Then change the Person.ts and Country.ts to export things on module.exports:

Person.ts:
module Domain {
    export class Country {
        name : string;
    }
}

// Hack for converting internal module to external module
declare var exports: any;
if (typeof exports != 'undefined') {
    module.exports = Domain.Country;
}

Country.ts:
module Domain {
    export class Country {
        name : string;
    }
}


// Hack for converting internal module to external module
declare var exports: any;
if (typeof exports != 'undefined') {
    module.exports = Domain.Country;
}



Definition of Calculator.ts:
///<reference path="../../typings/node/node.d.ts"/>

var isNode = typeof exports !== 'undefined' && this.exports !== exports;


module Domain.Calculator {

    export function multiply(multiplicand: number, multiplier: number): number {

        return multiplicand * multiplier;
    }

    export function divide(dividend: number, divisor: number): number {

        return null;
    }
}



if (isNode) {
    module.exports = Domain.Calculator;
}


Definition of FinancialCalculator.ts:
/// <reference path="../../typings/node/node.d.ts"/>

///<reference path="Calculator.ts"/>


var isNode = typeof exports !== 'undefined' && this.exports !== exports;

var calculator : typeof Domain.Calculator = isNode ? require('./Calculator') : Domain.Calculator;


module Domain.FinancialCalculator {

    export function applyInterest(amount: number, percentInterest: number): number {

        return calculator.multiply(amount, 1 + percentInterest);
    }

}


if (isNode) {
    module.exports = Domain.FinancialCalculator;
}


On next post, I'll show the difference between TypeScript's classes and module when it comes to proxyquire.


Happy Coding!

No comments:

Post a Comment