How to check for wrong number of parameters passed to a function
Asked Answered
B

1

9

I am writing a program using typescript and tslint as a linter. My current favorite list of rules is the following (tslint.json):

{
    "extends": "tslint:recommended",

    "rules": {
        "comment-format": [false, "check-space"],
        "eofline": false,
        "triple-equals": [false, "allow-null-check"],
        "no-trailing-whitespace": false,
        "one-line": false,
        "no-empty": false,
        "typedef-whitespace": false,
        "whitespace": false,
        "radix": false,
        "no-consecutive-blank-lines": false,
        "no-console": false,
        "typedef": [true,
            "variable-declaration",
            "call-signature",
            "parameter",
            "property-declaration",
            "member-variable-declaration"
        ],
        "quotemark": false,
        "no-any": true,
        "one-variable-per-declaration": false
    }

}

Although I am using Tslint it fails to catch a calling to a function with wrong number of parameters. For example I have the following function :

let displayTimer: Function = function(): void {
    document.getElementById('milliseconds').innerHTML = ms.toString();
    document.getElementById('seconds').innerHTML = seconds.toString();
    document.getElementById('minutes').innerHTML= minutes.toString();
};

And I am calling it with from inside another function like this :

let turnTimerOn: Function = function(): void {

    ms += interval;

    if (ms >= 1000)
    {
        ms = 0;
        seconds += 1;
    }

    if (seconds >= 60)
    {
        ms = 0;
        seconds = 0;
        minutes += 1;
    }

    displayTimer(1);
};

As you can see I am passing a parameter to the displayTimer function (in this case the number 1 but it could be anything else) and the linter is not catching that.

Bomber answered 22/7, 2016 at 12:54 Comment(3)
well, that's because it's not invalid javascript. it is perfectly valid to pass values you have not defined as parameters and later retrieve them in the function using the arguments.Tolmach
Thanks for pointing this out.I am coming from a Java/C# background so I want to be able to check for this type of mismatch.Any ideas?Bomber
Maybe I'm missing something but is there a reason the function is not declared as function displayTimer():void {? I think TS would better be able to check that. Right now all it's working off of for typing is let displayTimer:Function = ???. It doesn't know whether at some point you'll reassign null or some other function to it.Weathers
R
5

Just remove the type Function and TypeScript will check the signature:

let displayTimer = function(): void {
    // ...
};

displayTimer(1); // Error: Supplied parameters does not match any signature of call target

The inferred type of displayTimer is not Function (which accepts any signatures) but () => void.

See the code in the PlayGround.

Rosewater answered 22/7, 2016 at 13:43 Comment(5)
Thank you for your answer.You were right about typescript compiler that detects the error when I remove the Function type declaration.The problem is that with these tslint rules as soon as I remove the declaration I see that tslint complains about this removal (TSLint: expected variable declaration: 'displayTimer' to have a typedef (typedef))Bomber
Following your suggestion I've used the following code to declare and assign a value in the same line.It is a little ugly but it works: let displayTimer: () => void = function(): void{ document.getElementById('milliseconds').innerHTML = ms.toString(); document.getElementById('seconds').innerHTML = seconds.toString(); document.getElementById('minutes').innerHTML= minutes.toString(); };Bomber
@Bomber IMO, you should use inference where it can be used. let displayTimer: () => void = function(): void { /* ... */ } is not DRY.Rosewater
Can you explain the term DRY please?Thank you!Bomber
@Bomber Don't repeat yourself. Maybe you should consider the compilation option noImplicitAny of the TS compiler (see compilation options here).Rosewater

© 2022 - 2024 — McMap. All rights reserved.