microsoft/TypeScript · error · TypeError
Private method is not writable
Error message
Private method is not writable
What it means
Runtime TypeError from `__classPrivateFieldSet`. The helper throws immediately when `kind === "m"` (method): private methods are non-writable by design, so any assignment to one is rejected. Emitted for targets below ES2022; on native targets the same operation throws a different (spec-defined) TypeError.
Source
Thrown at src/compiler/factory/emitHelpers.ts:1350
*
* Writing to a private static set accessor (when defined, TS 4.3+):
* __classPrivateFieldSet(<any>, <constructor>, <any>, "a", <function>)
*
* Writing to a private static set accessor (when not defined, TS 4.3+):
* __classPrivateFieldSet(<any>, <constructor>, <any>, "a", void 0)
* NOTE: This always results in a runtime error.
*
* Writing to a private static method (TS 4.3+):
* __classPrivateFieldSet(<any>, <constructor>, <any>, "m", <function>)
* NOTE: This always results in a runtime error.
*/
const classPrivateFieldSetHelper: UnscopedEmitHelper = {
name: "typescript:classPrivateFieldSet",
importName: "__classPrivateFieldSet",
scoped: false,
text: `
var __classPrivateFieldSet = (this && this.__classPrivateFieldSet) || function (receiver, state, value, kind, f) {
if (kind === "m") throw new TypeError("Private method is not writable");
if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a setter");
if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot write private member to an object whose class did not declare it");
return (kind === "a" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value)), value;
};`,
};
/**
* Parameters:
* @param state — One of the following:
* - A WeakMap when the member is a private instance field.
* - A WeakSet when the member is a private instance method or accessor.
* - A function value that should be the undecorated class constructor when the member is a private static field, method, or accessor.
* @param receiver — The object being checked if it has the private member.
*
* Usage:
* This helper is used to transform `#field in expression` to
* `__classPrivateFieldIn(<weakMap/weakSet/constructor>, expression)`
*/
View on GitHub (pinned to b465fdbfe1)
Solutions
- Replace the private method with a private field holding a function if you genuinely need reassignment.
- Refactor so behavior varies through a settable dependency rather than reassigning the method.
- For tests, design seams (overridable protected methods, dependency injection) instead of patching privates.
- Raise `target` to ES2022+ to get the spec error directly, which is clearer in stack traces.
Example fix
// before
class C {
#m() { return 1; }
patch() { this.#m = () => 2; } // runtime TypeError
}
// after
class C {
#m: () => number = () => 1; // private field holding a function
patch() { this.#m = () => 2; }
} Defensive patterns
Strategy: validation
Validate before calling
// Disallow assignment to private methods at design time; if reassignment is needed, // model the slot as a field-typed function (see exampleFix).
Type guard
type IsMethod<T> = T extends (...a: any[]) => any ? true : false;
Prevention
- Treat private methods as immutable; use private function-valued fields when you need swapability.
- Don't try to monkey-patch private methods for tests — inject the dependency instead.
When it happens
Trigger: Assigning to a private method (`this.#m = fn`), in code compiled with the `__classPrivateFieldSet` helper. Reached both for instance and static private methods (`#m() {}` or `static #m() {}`).
Common situations: Attempting to swap/stub a private method for testing; refactor that confuses a private method with a private field; framework code that tries to monkey-patch methods on instances.
Related errors
- Private accessor was defined without a getter
- Cannot read private member from an object whose class did no
- Private accessor was defined without a setter
- Cannot write private member to an object whose class did not
- Cannot use 'in' operator on non-object
AI-assisted analysis of microsoft/TypeScript@b465fdbfe1 (2026-08-12).
Data as JSON: /api/errors/40dcfa64a9f41892.
Report an issue: GitHub.