Checking the argument types in Apps Script

I often waste a lot of time tracking down stupid bugs that are to do with passing the wrong kind of argument to a function. As you know, JavaScript is not strongly typed, and this leads to much sloppiness on my part. While writing RipDB - scriptDB emulator, which is a replication of the the old ScriptDB, I found I had no room for the kind of in flight changes i sometimes do to accommodate my own untidiness, so I decided to expand on Reporting file, function and line number in Apps Script, which is part of my cUseful library, to include a simple check at run time of arguments being passed versus what was expected. 

Here's how it works.

This function 

function validateArgs (funcArgs , funcTypes , optFail) {

}


where
  • funcArgs : an array of JavaScript items. Typically this would be the arguments received by a function. 
  • funcTypes : an array of strings describing what type these arguments should be
  • optFail: whether or not to fail if the types of funcArgs don't match the types described in funcTypes. Default is to throw an error
  • The function returns an object describing the first mismatch. If you choose not to throw an error on failure, the result's .ok property can be tested.

Examples

Before moving on to applying this to testing function arguments, let's look at some simple examples.

Valid checks

validateArgs (["abc",23,true,{"a":2}],  ["string","number","boolean","object"] );

It can also detect JavaScript objects
validateArgs ([new Date(), Date] ,  ["Date","function"] );

and Arrays
validateArgs ([[1,2],[{"a":2},{"b":3}]], ["Array.number","Array.object"] );

Optional or multiple types
validateArgs ([1,"w",false,new Date(),[3,4],[ "any","string","any","Array.any"] );

Missing arguments 
validateArgs( [1,2] , ["number","number","any"] );

Array validation for missing arguments
validateArgs( [1,2,["a","b","c"]] , ["number","number","any.string"] );

Custom objects - from libraries or you create yourself
validateArgs ( [myDb , results] , [DbAbstraction, Array.DbResults] );

and so on.

Validating function arguments

Of course the real reason for this function is to validate arguments arriving in a function  at run time against what was expected. One way is to repeat the function arguments.

function yourFunction ( arga , argb ) {
    cUseful.validateArgs ([arga,argb] , ["string","Array.object"]);
}


The arguments parameter can be tweaked to look like an array and passed over, so a better way is to do this.
    cUseful.validateArgs ( 
      Array.prototype.slice.call(arguments),
      [ "string" ,"Array.object"] 
    );

That way, the only thing you have to maintain is the expected types array and validateArgs will complain if you have less valid types specified than arguments arriving. 

Throwing an error

By default, it will throw an error when an argument is mismatched. However, passing the optFail parameter as false will not fail but return a results object like this, which shows the entire stack and what the problem was in the detail property. Even if you choose not to fail, this result will be written to the log file. You can access it like this

var result = cUseful.validateArgs ( youArgs, yourChecks , false);
if (!result.ok) {
    ...do something with the result object
}

You'll get this
{
    "ok": false,
    "location": [
        {
            "caller": "whereAmI",
            "line": "326",
            "file": "Code (cUseful)"
        },
        {
            "caller": "report",
            "line": "582",
            "file": "Code (cUseful)"
        },
        {
            "caller": "check",
            "line": "576",
            "file": "Code (cUseful)"
        },
        {
            "caller": "validateArgs",
            "line": "529",
            "file": "Code (cUseful)"
        },
        {
            "caller": "getMutationResults",
            "line": "30",
            "file": "RipDbMutation (cRipDB)"
        },
        {
            "caller": "unknown",
            "line": "204",
            "file": "RipDb (cRipDB)"
        },
        {
            "caller": "unknown",
            "line": "155",
            "file": "RipDb (cRipDB)"
        },
        {
            "caller": "unknown",
            "line": "110",
            "file": "Code"
        },
        {
            "caller": "unknown",
            "line": "1170",
            "file": "cDbAbstraction (cDbAbstraction)"
        },
        {
            "caller": "unknown",
            "line": "1236",
            "file": "cDbAbstraction (cDbAbstraction)"
        },
        {
            "caller": "unknown",
            "line": "258",
            "file": "Code (cNamedLock)"
        },
        {
            "caller": "doGuts_",
            "line": "1230",
            "file": "cDbAbstraction (cDbAbstraction)"
        },
        {
            "caller": "unknown",
            "line": "1124",
            "file": "cDbAbstraction (cDbAbstraction)"
        },
        {
            "caller": "test",
            "line": "69",
            "file": "Code"
        },
        {
            "caller": "unknown",
            "line": "54",
            "file": "Code"
        },
        {
            "caller": "tall",
            "line": "52",
            "file": "Code"
        }
    ],
    "detail": {
        "index": 1,
        "arrayElement": -1,
        "type": "object",
        "expected": "object",
        "got": "undefined"
    }
}

The code

Best way to get this is to include the cUseful library, or you can find on GitHub or below.




Many of the snippets in this section of the site are part of the cUseful library. You can find the details below.

https://script.google.com/macros/s/AKfycbwZ2Hht93wTNzvRmYINYF7obaOHciBXWcP_wAiEtyGq70_x3cI/exec?list=cUseful


For more like this, see  Google Apps Scripts snippets. Why not join our forum,follow the blog or follow me on twitter to ensure you get updates when they are available. 

You want to learn Google Apps Script?

Learning Apps Script, (and transitioning from VBA) are covered comprehensively in my my book, Going Gas - from VBA to Apps script, available All formats are available now from O'Reilly,Amazon and all good bookshops. You can also read a preview on O'Reilly

If you prefer Video style learning I also have two courses available. also published by O'Reilly.
Google Apps Script for Developers and Google Apps Script for Beginners.





Comments