microsoft/TypeScript · error · TypeError

Private accessor was defined without a getter

Error message

Private accessor was defined without a getter

What it means

Runtime TypeError thrown by the `__classPrivateFieldGet` downlevel helper that TypeScript emits when transpiling private accessors to targets below ES2022. The helper throws when `kind === "a"` (an accessor) but no getter function `f` was passed — i.e. the private accessor is write-only (declared with only a `set`). The compiler never throws this; only the emitted JavaScript does, when the write-only accessor is read.

Source

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

 *      __classPrivateFieldGet(<any>, <constructor>, "f", <{ value: any }>)
 *
 * Reading from a private static get accessor (when defined, TS 4.3+):
 *      __classPrivateFieldGet(<any>, <constructor>, "a", <function>)
 *
 * Reading from a private static get accessor (when not defined, TS 4.3+):
 *      __classPrivateFieldGet(<any>, <constructor>, "a", void 0)
 *      NOTE: This always results in a runtime error.
 *
 * Reading from a private static method (TS 4.3+):
 *      __classPrivateFieldGet(<any>, <constructor>, "m", <function>)
 */
const classPrivateFieldGetHelper: UnscopedEmitHelper = {
    name: "typescript:classPrivateFieldGet",
    importName: "__classPrivateFieldGet",
    scoped: false,
    text: `
            var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (receiver, state, kind, f) {
                if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a getter");
                if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it");
                return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
            };`,
};

/**
 * Parameters:
 *  @param receiver — The object on which the private member will be set.
 *  @param state — One of the following:
 *      - A WeakMap used to store a private instance field.
 *      - A WeakSet used as an instance brand for private instance methods and accessors.
 *      - A function value that should be the undecorated class constructor used to brand check private static fields, methods, and accessors.
 *  @param value — The value to set.
 *  @param kind — (optional pre TS 4.3, required for TS 4.3+) One of the following values:
 *       - undefined — Indicates a private instance field (pre TS 4.3).
 *       - "f" — Indicates a private field (instance or static).
 *       - "m" — Indicates a private method (instance or static).
 *       - "a" — Indicates a private accessor (instance or static).

View on GitHub (pinned to b465fdbfe1)

Solutions

  1. Add a `get` accessor to the private member so reads are valid.
  2. Raise `target` to `ES2022`+ so native private fields are emitted and the helper is not generated.
  3. Stop reading the write-only accessor at that call site — only assign to it.
  4. If invoking the helper manually, pass a non-null getter function for kind "a".

Example fix

// before
class C {
  set #acc(v: number) {}        // setter only, no getter
  read() { return this.#acc; }  // runtime TypeError
}
// after
class C {
  #v = 0;
  get #acc() { return this.#v; }
  set #acc(v: number) { this.#v = v; }
  read() { return this.#acc; }
}
Defensive patterns

Strategy: type-guard

Validate before calling

// At authoring time the compiler flags reads of write-only accessors.
// If you bypassed types with `any`, restore them so the read is caught statically:
function readAcc(c: C) { return (c as any).#acc; } // avoid `any` casts on private members

Type guard

// Ensure every private accessor you read has a getter (compile-time):
type HasGetter<T> = T extends { readonly get: infer G } ? G : never;

Prevention

When it happens

Trigger: Reading a private accessor that has only a setter (`set #x(v){}` with no `get #x`), in code compiled with the `__classPrivateFieldGet` helper (target below ES2022, or downlevel private-member emit). Also reached by calling the helper directly with kind "a" and a falsy fourth argument.

Common situations: Downleveling a class that contains a setter-only private accessor and then reading that accessor from a method; refactoring a public accessor pair into private members and forgetting the getter; targeting older runtimes while using ES2022 private syntax.

Related errors


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