Below if I import Entity
I get the posts's subject error (TypeError: Object prototype may only be an Object or null: undefined), but if I replace the import with the actual Entity
declaration the code runs fine.
This is Customer.ts
in the form that produces the error when I run the code with ts-node
:
index.ts
export { Customer } from "./Customer";
export { Entity } from "./Entity";
Customer.ts
import { Entity } from "./index";
export class Customer extends Entity {
sku: string;
constructor(po: any) {
super();
this.sku = po.sku;
}
}
Entity.ts
export abstract class Entity {
id?: string;
}
Run.ts (The test code)
import {Customer} from "./";
let c = new Customer({
name: "Bob"
});
console.log(c);
If I replace the Entity
import with the declaration like this:
export abstract class Entity {
id?: string;
}
export class Customer extends Entity {
sku: string;
constructor(po: any) {
super();
this.sku = po.sku;
}
}
Then Run.ts
logs this:
Customer { sku: undefined }
In other words it runs fine and produces no errors. Thoughts?
As I suspected, your original program has circular imports. Run.ts
imports index.ts
, which imports Customer.ts
, which imports index.ts
again. Since index.ts
is already in the process of loading and itself depends on Customer.ts
, the import { Entity } from "./index";
just binds the Entity
of index.ts
(which is not set yet) to the Entity
of Customer.ts
, and execution proceeds even though index.ts
isn't finished loading. Then Entity
is undefined at the time you try to extend it. You might argue that a circular import should be an error or that JavaScript engines should use some other algorithm that correctly handles your scenario; I'm not qualified to comment on why the current design was chosen. (Others feel free to add information about this.)
As you saw, changing Customer.ts
to import from ./Entity
directly instead of ./index
breaks the cycle, and everything works as expected. Another solution would be to reverse the order of imports in index.ts
.