microsoft/TypeScript · error · TypeError

Private accessor was defined without a setter

Error message

Private accessor was defined without a setter

What it means

Runtime TypeError from `__classPrivateFieldSet`. The helper throws when `kind === "a"` (accessor) and no setter function `f` was supplied — the private accessor is read-only (declared with only a `get`). Mirror of error 20, but on the write path.

Source

Thrown at src/compiler/factory/emitHelpers.ts:1351

 * 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)`
 */
const classPrivateFieldInHelper: UnscopedEmitHelper = {

View on GitHub (pinned to b465fdbfe1)

Solutions

  1. Add a `set` to the private accessor if writes are intended.
  2. Stop assigning to the read-only accessor at that call site.
  3. Raise `target` to ES2022+ for native semantics and clearer errors.
  4. Back the accessor with a writable private field and route writes through an explicit setter.

Example fix

// before
class C {
  get #ro() { return 42; }
  set() { this.#ro = 1; }   // runtime TypeError
}
// after
class C {
  #v = 42;
  get #ro() { return this.#v; }
  set #ro(x: number) { this.#v = x; }
  set() { this.#ro = 1; }
}
Defensive patterns

Strategy: validation

Validate before calling

// Only assign to accessors you have explicitly declared a setter for;
// keep the get/set pair together when authoring.

Type guard

type HasSetter<T> = T extends { readonly set: infer S } ? S : never;

Prevention

When it happens

Trigger: Assigning to a private accessor that has only a getter (`get #x() { ... }` with no `set #x`), compiled with the `__classPrivateFieldSet` helper (target below ES2022).

Common situations: Declaring a computed read-only private accessor and later trying to assign it; migrating readonly fields to accessors without adding setters; framework code that writes back to computed properties.

Related errors


AI-assisted analysis of microsoft/TypeScript@b465fdbfe1 (2026-08-12). Data as JSON: /api/errors/ea2e41e344ff13e2. Report an issue: GitHub.