TypeError: Object prototype may only be an Object or null: undefined
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
.
Ole
Updated on July 09, 2022Comments
-
Ole almost 2 years
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 actualEntity
declaration the code runs fine.This is
Customer.ts
in the form that produces the error when I run the code withts-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?
-
Ole over 5 yearsExcellent observation! I reported it as a bug just in case it can help Typescript design better handling / error reporting for this scenario.
-
Ole over 5 yearsPerhaps the compiler could detect the circular dependency, and just replace the
./
path with./Entity
. They are equivalent, and since it's runtime code everyone is happy ...