deepkit / deepkit-framework

A new full-featured and high-performance TypeScript framework
https://deepkit.io/
MIT License
3.24k stars 124 forks source link

Bug? Serializer throws on tuples with null union eg [number | null, number | null] #603

Closed lionelhorn closed 3 months ago

lionelhorn commented 3 months ago

The following test will throw when executing cast<T>

More context in discord

  test("cast literal obj having typed tuple [number | null, number | null] as nested prop", () => {
    type MinMax = [min: number | null, max: number | null];

    class T {
      building?: {
        area?: MinMax
      }
    }

    // const d = JSON.parse('{"building":{"area":[120,null]}}');

    const data: T = cast<T>({
      building: {
        area: [120, null]
      }
    });

    const errors = validate<T>(data);
    expect(errors.length).toBe(0);
  });
 Error: Could not build function(_context,typeSettings,UnpopulatedCheck,UnpopulatedCheckReturnSymbol,jit_0,isGroupAllowed,jit_1,jit_2,guard_number_0,Number,ValidationError,stringifyValueWithType,guard_number_1,guard_null_0,guard_number_2,guard_null_1,ValidationErrorItem,guard_number_3,guard_number_4,guard_null_2,guard_number_5,guard_null_3): SyntaxError: Identifier 'oldErrors' has already been declared
 'use strict';

return function self(data, state, _path) {
    'use strict';

    var result;
    if (_path === undefined) _path = '';

    state = state ? state : {};

    let __0;
    let i_0 = 0;
    result = [];

    __0 = undefined;

    const oldErrors = state.errors;
    if (state.errors) state.errors = [];

    //type guard for union
    if (false) {} else if (state.loosely !== false && guard_number_0(data, state, _path + '.' + i_0, i_0)) {
        //type = number, specificality=-0.5

        __0 = 'number' !== typeof data[i_0] && state.loosely !== false ? Number(data[i_0]) : data[i_0];
        if (isNaN(__0)) throw ValidationError.from([{
            code: 'type',
            path: _path + '.' + i_0,
            message: 'Cannot convert ' + data[i_0] + ' to ' + "number"
        }])
    } else if (guard_number_1(data, state, _path + '.' + i_0, i_0)) {
        //type = number, specificality=1

        __0 = 'number' !== typeof data[i_0] && state.loosely !== false ? Number(data[i_0]) : data[i_0];
        if (isNaN(__0)) throw ValidationError.from([{
            code: 'type',
            path: _path + '.' + i_0,
            message: 'Cannot convert ' + data[i_0] + ' to ' + "number"
        }])
    } else if (guard_null_0(data, state, _path + '.' + i_0, i_0)) {
        //type = null, specificality=1

        __0 = null;
    } else if (guard_number_2(data, state, _path + '.' + i_0, i_0)) {
        //type = number, specificality=2

        __0 = 'number' !== typeof data[i_0] && state.loosely !== false ? Number(data[i_0]) : data[i_0];
        if (isNaN(__0)) throw ValidationError.from([{
            code: 'type',
            path: _path + '.' + i_0,
            message: 'Cannot convert ' + data[i_0] + ' to ' + "number"
        }])
    } else if (guard_null_1(data, state, _path + '.' + i_0, i_0)) {
        //type = null, specificality=2

        __0 = null;
    } else {

        if (state.errors) {
            __0 = false;
            state.errors = oldErrors;
        }

        if (state.errors) state.errors.push(new ValidationErrorItem(_path + '.' + i_0, "type", "No valid union member found. Valid: number | null", data[i_0]));
    }
    state.errors = oldErrors;

    if (__0 !== undefined) {
        result.push(__0);
    } else if (false) {
        result.push(undefined);
    }
    i_0++;

    __0 = undefined;

    const oldErrors = state.errors;
    if (state.errors) state.errors = [];

    //type guard for union
    if (false) {} else if (state.loosely !== false && guard_number_3(data, state, _path + '.' + i_0, i_0)) {
        //type = number, specificality=-0.5

        __0 = 'number' !== typeof data[i_0] && state.loosely !== false ? Number(data[i_0]) : data[i_0];
        if (isNaN(__0)) throw ValidationError.from([{
            code: 'type',
            path: _path + '.' + i_0,
            message: 'Cannot convert ' + data[i_0] + ' to ' + "number"
        }])
    } else if (guard_number_4(data, state, _path + '.' + i_0, i_0)) {
        //type = number, specificality=1

        __0 = 'number' !== typeof data[i_0] && state.loosely !== false ? Number(data[i_0]) : data[i_0];
        if (isNaN(__0)) throw ValidationError.from([{
            code: 'type',
            path: _path + '.' + i_0,
            message: 'Cannot convert ' + data[i_0] + ' to ' + "number"
        }])
    } else if (guard_null_2(data, state, _path + '.' + i_0, i_0)) {
        //type = null, specificality=1

        __0 = null;
    } else if (guard_number_5(data, state, _path + '.' + i_0, i_0)) {
        //type = number, specificality=2

        __0 = 'number' !== typeof data[i_0] && state.loosely !== false ? Number(data[i_0]) : data[i_0];
        if (isNaN(__0)) throw ValidationError.from([{
            code: 'type',
            path: _path + '.' + i_0,
            message: 'Cannot convert ' + data[i_0] + ' to ' + "number"
        }])
    } else if (guard_null_3(data, state, _path + '.' + i_0, i_0)) {
        //type = null, specificality=2

        __0 = null;
    } else {

        if (state.errors) {
            __0 = false;
            state.errors = oldErrors;
        }

        if (state.errors) state.errors.push(new ValidationErrorItem(_path + '.' + i_0, "type", "No valid union member found. Valid: number | null", data[i_0]));
    }
    state.errors = oldErrors;

    if (__0 !== undefined) {
        result.push(__0);
    } else if (false) {
        result.push(undefined);
    }
    i_0++;

    return result;

};
    at CompilerContext.build (file:///C:/PROG/deepform/node_modules/.pnpm/@deepkit+core@1.0.1-alpha.147/node_modules/@deepkit/core/src/compiler.ts:115:19)
    at buildFunction (file:///C:/PROG/deepform/node_modules/.pnpm/@deepkit+type@1.0.1-alpha.151_@deepkit+core@1.0.1-alpha.147/node_modules/@deepkit/type/src/serializer.ts:775:34)
    at executeTemplates (file:///C:/PROG/deepform/node_modules/.pnpm/@deepkit+type@1.0.1-alpha.151_@deepkit+core@1.0.1-alpha.147/node_modules/@deepkit/type/src/serializer.ts:850:25)
    at createConverterJSForMember (file:///C:/PROG/deepform/node_modules/.pnpm/@deepkit+type@1.0.1-alpha.151_@deepkit+core@1.0.1-alpha.147/node_modules/@deepkit/type/src/serializer.ts:874:19)
    at serializeObjectLiteral (file:///C:/PROG/deepform/node_modules/.pnpm/@deepkit+type@1.0.1-alpha.151_@deepkit+core@1.0.1-alpha.147/node_modules/@deepkit/type/src/serializer.ts:1234:23)
    at executeTemplates (file:///C:/PROG/deepform/node_modules/.pnpm/@deepkit+type@1.0.1-alpha.151_@deepkit+core@1.0.1-alpha.147/node_modules/@deepkit/type/src/serializer.ts:843:13)
    at createConverterJSForMember (file:///C:/PROG/deepform/node_modules/.pnpm/@deepkit+type@1.0.1-alpha.151_@deepkit+core@1.0.1-alpha.147/node_modules/@deepkit/type/src/serializer.ts:874:19)
    at serializeObjectLiteral (file:///C:/PROG/deepform/node_modules/.pnpm/@deepkit+type@1.0.1-alpha.151_@deepkit+core@1.0.1-alpha.147/node_modules/@deepkit/type/src/serializer.ts:1234:23)
    at executeTemplates (file:///C:/PROG/deepform/node_modules/.pnpm/@deepkit+type@1.0.1-alpha.151_@deepkit+core@1.0.1-alpha.147/node_modules/@deepkit/type/src/serializer.ts:843:13)
    at createSerializeFunction (file:///C:/PROG/deepform/node_modules/.pnpm/@deepkit+type@1.0.1-alpha.151_@deepkit+core@1.0.1-alpha.147/node_modules/@deepkit/type/src/serializer.ts:241:11)
lionelhorn commented 3 months ago

Some failing tests

https://github.com/lionelhorn/deepkit-framework/blob/603-fix-tuples-cast/packages/type/tests/issues/typed-tuples.spec.ts in current master 5ae467e