Async creation function requires the usage of `new this()` not `new ClassName()`
tegefaulkes opened this issue · 4 comments
Describe the bug
I have a class that is decorated with a decorator called CreateDestroyStartStop. This augments the class with some logic regarding locking and asynchronous usage. It adds a readonly parameter readonly [initLock]: RWLockWriter; where initLock is a symbol const initLock = Symbol('initLock').
We use a static create method when instantiating our class. This returns a new instance of our class.
static async createXFails() {
return new X();
}What we've found is that, if this static create function constructs the class using new X() the resulting instance of the class is not properly decorated. Specifically the readonly [initLock]: RWLockWriter; that the decorator should've added is undefined.
Conversely if we construct the class using new this(), the property is properly defined and everything works.
static async createXWorks() {
return new this();
}It seems that constructing the class with new x() is undecorated while new this() is decorated.
Input code
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();Config
No response
Playground link
No response
Expected behavior
After using the static createX method to instantiate the class, the readonly [initLock]: RWLockWriter; property added by the decorator should be defined. Any usage of this[initLock] should be defined and any method calls such as this.[initLock].isLocked() should succeed.
Specifically, in the provided code example, calling x.thing() should not throw any errors.
Actual behavior
After using the static create method createXFail(), the property readonly [initLock]: RWLockWriter; added by the decorator is undefined. Calling x.thing() which is a method decorated with @ready() which accesses the readonly [initLock]: RWLockWriter; with this.[initLock].isLocked() results in the following error.
> @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)
Version
1.3.59
Additional context
We have a downstream issue for tracking this at MatrixAI/js-async-init#25.
Please post your config and playground link
I'll reopen once you add them.
I simplified the example a little for the playground. The example in the playground exhibits the problem on my local system. but when I take the compiled code from the playground run it in node I don't get the expected problem.
.swcrc taken from the playground is.
{
"jsc": {
"parser": {
"syntax": "typescript",
"tsx": false,
"decorators": true
},
"target": "es2021",
"loose": false,
"minify": {
"compress": false,
"mangle": false
}
},
"module": {
"type": "es6"
},
"minify": false,
"isModule": true
}We don't use a .swcrc file for our project, We've configured ts-node with tsconfig.json.
{
"compilerOptions": {
"outDir": "./dist",
"tsBuildInfoFile": "./dist/tsbuildinfo",
"incremental": true,
"sourceMap": true,
"declaration": true,
"allowJs": true,
"strictNullChecks": true,
"noImplicitAny": false,
"experimentalDecorators": true,
"esModuleInterop": true,
"allowSyntheticDefaultImports": true,
"resolveJsonModule": true,
"moduleResolution": "node",
"module": "CommonJS",
"target": "ES2021",
"baseUrl": "./src",
"paths": {
"@": ["index"],
"@/*": ["*"]
},
"noEmit": true
},
"include": [
"./src/**/*",
"./src/**/*.json",
"./tests/**/*",
"./scripts/**/*",
"./benches/**/*"
],
"ts-node": {
"require": ["tsconfig-paths/register"],
"transpileOnly": true,
"swc": true
}
}I hope this helps.
This closed issue has been automatically locked because it had no new activity for a month. If you are running into a similar issue, please create a new issue with the steps to reproduce. Thank you.