Skip to content

Incorrect transform for optional parameters #43

@matAtWork

Description

@matAtWork

The length check for a Parameter list tuple is too strict in the case of optional parameters (or in fact any array where the final element(s) can validly be undefined).

Here's a case to reproduce the issue:

import * as assert from 'assert';
import { createIs } from '../index';

describe('is', () => {
    function foo(_a: number, _b?: string) { return; }
    type FooParams = Parameters<typeof foo>;

    const isFooParams = createIs<FooParams>();

    describe('isFooParams', () => {
        it('should return true for valid parameters, optional or not', () => {
            assert.deepStrictEqual(isFooParams([1, 'a']), true);
            assert.deepStrictEqual(isFooParams([1]), true);
            assert.deepStrictEqual(isFooParams([1, undefined]), true);
            assert.deepStrictEqual(isFooParams([1, null]), false);
        });
    });
});

The second assert (incorrectly) fails: element [1] of the array is indeed undefined.

In the generated output (below) there is an inappropriate test for Array.length===2.

"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const assert = require("assert");
const index_1 = require("../index");
describe('is', () => {
    function foo(_a, _b) { return; }
    const isFooParams = index_1.createIs(object => {
        var path = ["$"]; 
        function _number(object) {
            if (typeof object !== "number")
                return "validation failed at " + path.join(".") + ": expected a number";
            else
                return null;
        } 
        function _undefined(object) {
            if (object !== undefined)
                return "validation failed at " + path.join(".") + ": expected undefined";
            else
                return null;
        } 
        function _string(object) {
            if (typeof object !== "string")
                return "validation failed at " + path.join(".") + ": expected a string";
            else
                return null;
        } 
        function su__undefined__string_eu(object) {
            var conditions = [_undefined, _string]; for (const condition of conditions) {
                var error = condition(object);
                if (!error)
                    return null;
            } return "validation failed at " + path.join(".") + ": there are no valid alternatives";
        } 
        function st__number_su__undefined__string_eu_et_9_396(object) {
/* HERE: array.length might be <= 2 since all the final elements after length=1 can validly be undefined */
            if (!Array.isArray(object) || object.length !== 2) 
                return "validation failed at " + path.join(".") + ": expected an array of length 2"; {
                path.push("[0]");
                var error = _number(object[0]);
                path.pop();
                if (error)
                    return error;
            } {
                path.push("[1]");
                var error = su__undefined__string_eu(object[1]);
                path.pop();
                if (error)
                    return error;
            } return null;
        } var error = st__number_su__undefined__string_eu_et_9_396(object); return error;
    });
    describe('isFooParams', () => {
        it('should return true for valid parameters, optional or not', () => {
            assert.deepStrictEqual(isFooParams([1, 'a']), true);
            assert.deepStrictEqual(isFooParams([1]), true);
            assert.deepStrictEqual(isFooParams([1, undefined]), true);
            assert.deepStrictEqual(isFooParams([1, null]), false);
        });
    });
});

Output

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions