MatrixAI / js-async-init

Asynchronous initialization and deinitialization decorators for JavaScript/TypeScript applications

Home Page:https://polykey.com

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Async creation function requires the usage of `new this()` not `new ClassName()`

CMCDragonkai opened this issue · comments

Describe the bug

When using CreateDestroy or CreateDestroyStartStop, it is necessary for the async creation function to use new this().

If you use new ClassName() then it will fail due to the constructor not referring to the decorated class constructor.

This only seems to occur with SWC, TSC works fine.

I have a memory of having reported this already upstream to SWC, but evidently it's not fixed and I cannot find the issue I reported or saw...

@tegefaulkes

To Reproduce

  1. Create a prototype script with class X with CreateDestroyStartStop and a @ready method
  2. Run it with npm run ts-node -- ./test.ts
  3. See the result between swc enabled or disabled
  4. Change to new this and it should work!

Expected behavior

The SWC should behave the same as TSC.

Here is the example that demonstrates the problem.

import { CreateDestroyStartStop, ready } from '@matrixai/async-init/dist/CreateDestroyStartStop';

interface X extends CreateDestroyStartStop {}
@CreateDestroyStartStop()
class X {
  static async createXWorks() {
    return new this();
  }
  static async createXFails() {
    return new X();
  }
  async start() {}
  async stop() {}
  async destroy() {}
  
  @ready()
  async thing() {}
}


async function mainWorks () {
  const x = await X.createXWorks();
  await x.start()
  await x.thing();
  await x.stop();
  await x.destroy();
}

async function mainFails () {
  const x = await X.createXFails();
  await x.start()
  await x.thing();
  await x.stop();
  await x.destroy();
}

// void mainWorks();
void mainFails();

mainFails fails with the following error.

[nix-shell:~/matixWorkspace/gitRepos/js-db]$ npm run ts-node -- test.ts

> @matrixai/db@5.1.0 ts-node
> ts-node "test.ts"

TypeError: Cannot read properties of undefined (reading 'isLocked')
    at X.thing (/home/faulkes/matixWorkspace/gitRepos/js-db/node_modules/@matrixai/async-init/src/CreateDestroyStartStop.ts:189:30)
    at mainFails (/home/faulkes/matixWorkspace/gitRepos/js-db/test.ts:44:11)

The decorators here are setting up some state in the constructor. Relevant to this problem it's creating mutex lock and storing it in a property using a symbol as the key.

const initLock = Symbol('initLock');

// Decorator is adding this to the class.
  readonly [initLock]: RWLockWriter;

// The @ready decorator is trying to access it.
this[initLock].isLocked('write')

Created upstream issue at swc-project/swc#7426

The upstream wants a playground example showing the problem. I'm going to create one and update the issue.

Note that this is not a bug of this library. Users should just make sure to use new this() in their creation functions.

However in this project, we can change all of our tests and examples to use new this().

I've updated all the examples and tests to use new this() in 76bc9e3.

I think we can close this for now, as upstream will track that bug. We just have to be aware of this.

@amydevs make sure you know about this.