Using Object.defineProperty on a class field does not work as expected in my NextJS project (but it works just fine in a NodeJS program) #87165
-
SummaryI created my Next.js 16.0.10 (Turbopack) project using The below is a very simple example of the issue I am having. I am simply trying to override the class-defined NodeJS (expected results) NextJS In all of my code, outside NextJS, this works as expected. Bringing this pattern into a NextJS project causes the failure. I can get it to work in NextJS if I apply the I assume that this is an issue related to some TypeScript or NextJS config, but I am not sure. THIS WAS TAKEN FROM A FILE IN MY NEXTJS PROJECT AT /api/instance/route.ts THIS WAS TAKEN FROM A FILE IN MY NEXTJS PROJECT AT /api/prototype/route.ts Additional informationNo response ExampleNo response |
Beta Was this translation helpful? Give feedback.
Replies: 3 comments 2 replies
-
|
This behavior is caused by TypeScript's What's happening: When // Your TypeScript
class MyClass {
public myPublicField: string;
}
// Compiled JavaScript (with useDefineForClassFields: true)
class MyClass {
constructor() {
Object.defineProperty(this, "myPublicField", {
enumerable: true,
configurable: true,
writable: true,
value: void 0
});
}
}This instance property shadows your prototype property, which is why Solutions:
class MyClass {
protected _myProtectedField: string;
declare public myPublicField: string; // <-- declare prevents emission
}
{
"compilerOptions": {
"useDefineForClassFields": false
}
}(Note: this might have other side effects with your target/libs)
class MyClass {
protected _myProtectedField: string;
get myPublicField(): string {
return this._myProtectedField;
}
set myPublicField(value: string) {
this._myProtectedField = typeof value === 'string' ? value.toUpperCase() : value;
}
}The |
Beta Was this translation helpful? Give feedback.
-
|
As the other comment says, this is caused by TS compile output:
The one takeaway though, https://www.typescriptlang.org/tsconfig/#useDefineForClassFields:
So, what you observe when using it in Next.js is what the behavior will be, eventually... from MDN, https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Classes/Public_class_fields:
I think the get/set approach: public get myPublicField(): string {
return this._myProtectedField;
}
public set myPublicField(value: string) {
this._myProtectedField = value.toUpperCase();
}Is the right approach here. Though just like the |
Beta Was this translation helpful? Give feedback.
-
|
Thank you, @tt-a1i and @icyJoseph, for responding with this great information. Using the I will say that I generated a new project and added the Thanks again! |
Beta Was this translation helpful? Give feedback.
This behavior is caused by TypeScript's
useDefineForClassFieldssetting, which is enabled by default in Next.js (because it targets ES2022+).What's happening:
When
useDefineForClassFields: true, TypeScript compiles class fields usingObject.definePropertydirectly on the instance in the constructor:This instance property shadows your prototype property, which is why
defin…