Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Class instances cloned using klona/full do not run field initializers #43

Open
gebsh opened this issue Apr 3, 2023 · 0 comments
Open

Comments

@gebsh
Copy link

gebsh commented Apr 3, 2023

When cloning instances of classes containing instance fields, their initializers are not run:

import { klona as klonaFull } from 'klona/full';

class Foo {
    foo = ( console.log( 'initializing' ), 0 );
}

const foo1 = new Foo();
const foo2 = klonaFull( foo1 );

The preceding example logs initializing only once, even though I'd expect the log to be printed twice.

This bug is not present in klona/lite and klona, most likely due to the fact that they have a branch detecting constructor functions:

import { klona as klonaLite } from 'klona/lite';
import { klona } from 'klona';

class Foo {
    foo = ( console.log( 'initializing' ), 0 );
}

const foo1 = new Foo();
const foo2 = klonaLite( foo1 );
const foo3 = klona( foo1 );

Here, initializing is correctly logged three times.

This behavior has some implications. For example, TypeScript 5.0 supports the newest decorators proposal, and it transpiles such decorators to similar code. The following example:

function log( target: unknown, ctx: ClassFieldDecoratorContext ): void {
    ctx.addInitializer( () => {
        console.log( 'initializing' );
    } );
}

class Foo {
    @log
    foo = 0;
}

is transpiled by the TypeScript compiler as follows:

function log(target, ctx) {
    ctx.addInitializer(() => {
        console.log("initializing");
    });
}
let Foo = (() => {
    let _instanceExtraInitializers = [];
    let _foo_decorators;
    let _foo_initializers = [];
    return class Foo {
        static {
            _foo_decorators = [log];
            __esDecorate(
                null,
                null,
                _foo_decorators,
                {
                    kind: "field",
                    name: "foo",
                    static: false,
                    private: false,
                    access: {
                        has: (obj) => "foo" in obj,
                        get: (obj) => obj.foo,
                        set: (obj, value) => {
                            obj.foo = value;
                        },
                    },
                },
                _foo_initializers,
                _instanceExtraInitializers
            );
        }
        foo =
            (__runInitializers(this, _instanceExtraInitializers),
            __runInitializers(this, _foo_initializers, 0));
    };
})();

Note that some helpers (such as __esDecorate) were omitted for brevity.

When cloning objects that use decorators using klona/full, initializers added via ctx.addInitializer() are not run.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant