> ## Documentation Index
> Fetch the complete documentation index at: https://docs.syntblaze.com/llms.txt
> Use this file to discover all available pages before exploring further.

# TypeScript Private Setter

A private setter in TypeScript is a class member configuration where the `set` accessor is assigned a more restrictive access modifier (`private` or `protected`) than its corresponding `get` accessor. Introduced in TypeScript 4.3, this feature allows a property to be publicly readable during static analysis while restricting mutation strictly to the internal lexical scope of the class.

## Syntax

To implement a private setter, apply the `private` (or `protected`) keyword directly to the `set` method declaration, while leaving the `get` method with a broader visibility modifier (typically `public`).

```typescript theme={"dark"}
class StateContainer {
    private _internalCount: number = 0;

    // Publicly accessible accessor
    public get count(): number {
        return this._internalCount;
    }

    // Internally restricted mutator
    private set count(value: number) {
        this._internalCount = value;
    }

    public increment(): void {
        // Valid: Internal class methods can invoke the private setter
        this.count++; 
    }
}

const container = new StateContainer();
console.log(container.count); // Valid: Returns 0
container.count = 5;          // Error: Property 'count' cannot be assigned to because it is a read-only property outside the class.
```

## Technical Constraints and Rules

1. **Visibility Hierarchy:** The access modifier on the setter must be strictly more restrictive than the modifier on the getter. A `public` getter can pair with a `protected` or `private` setter. A `protected` getter can pair with a `private` setter. You cannot define a `private` getter with a `public` setter.
2. **Implicit Getter Visibility:** If no access modifier is explicitly defined on the getter, it defaults to `public`. The setter must then explicitly declare its narrower scope.
3. **Type Compatibility:** While TypeScript 4.3+ allows getters and setters to have different types, the type returned by the getter must be assignable to the type accepted by the setter.
4. **Compile-Time Enforcement:** The `private` keyword is a TypeScript-specific construct. The access restriction is enforced entirely by the TypeScript compiler during static analysis.
5. **Runtime Erasure:** Upon compilation to JavaScript, the `private` modifier is erased. The resulting JavaScript will output standard `get` and `set` functions on the class prototype. Because JavaScript property descriptors cannot have mixed runtime visibility, the setter remains publicly accessible at runtime.

## ECMAScript Runtime Equivalent

To achieve strict runtime encapsulation that mirrors the behavior of a TypeScript private setter, you cannot use the `private set` syntax, as it exposes the setter in the emitted JavaScript. Instead, you must omit the `set` accessor entirely—making the property strictly read-only from the outside—and mutate an ECMAScript private field (`#`) directly from within internal class methods.

```typescript theme={"dark"}
class RuntimeStateContainer {
    // ECMAScript private field (hard runtime privacy)
    #internalCount: number = 0;

    // Public getter exposes the value
    public get count(): number {
        return this.#internalCount;
    }

    // No setter is defined on the property descriptor.
    // Internal mutations target the private field directly.
    public increment(): void {
        this.#internalCount++;
    }
}

const runtimeContainer = new RuntimeStateContainer();
console.log(runtimeContainer.count); // 0
runtimeContainer.count = 5;          // TypeError at runtime: Cannot set property count of #<RuntimeStateContainer> which has only a getter
```

<div
  style={{ 
display: "flex", 
justifyContent: "space-between", 
alignItems: "center", 
maxWidth: "754px", 
padding: "1rem 0",
marginBottom: "24px"
}}
>
  <span style={{ fontWeight: "bold", fontSize: "1.25rem", color: "var(--tw-prose-headings)", fontFamily: "Inter, ui-sans-serif, system-ui, sans-serif" }}>Tired of Poor TypeScript Skills? Fix That With Deep Grasping!</span>

  <a
    href="https://syntblaze.com"
    target="_blank"
    style={{ 
  marginLeft: "24px",
  textDecoration: "none", 
  backgroundColor: "#007AFF",
  color: "#ffffff", 
  padding: "6px 16px", 
  borderRadius: "16px",
  fontSize: "0.9rem",
  fontWeight: "600",
  textAlign: "center",
  transition: "background-color 0.2s ease"
}}
  >
    Learn More
  </a>
</div>

<div style={{ display: "flex", gap: "12px", flexWrap: "wrap" }}>
  <img src="https://mintcdn.com/syntblazellc/-L0ums_2lctDSZ1l/images/skill-tracking.png?fit=max&auto=format&n=-L0ums_2lctDSZ1l&q=85&s=b9b0305c93bb501c9e767b5c76c88835" style={{ width: "30%", minWidth: 60 }} width="621" height="1344" data-path="images/skill-tracking.png" />

  <img src="https://mintcdn.com/syntblazellc/23tyuOzaWS88qFlc/images/nuggets.png?fit=max&auto=format&n=23tyuOzaWS88qFlc&q=85&s=c86c80197299762989e9b882419b2109" style={{ width: "30%", minWidth: 60 }} width="621" height="1344" data-path="images/nuggets.png" />

  <img src="https://mintcdn.com/syntblazellc/-L0ums_2lctDSZ1l/images/bite-sized-exercises.png?fit=max&auto=format&n=-L0ums_2lctDSZ1l&q=85&s=a65f9a38c37ff28ab73ed783c53c60e3" style={{ width: "30%", minWidth: 60 }} width="621" height="1344" data-path="images/bite-sized-exercises.png" />
</div>

<div style={{ display: "flex", gap: "12px", flexWrap: "wrap", marginTop: "12px" }}>
  <img src="https://mintcdn.com/syntblazellc/-L0ums_2lctDSZ1l/images/mastery-chain.png?fit=max&auto=format&n=-L0ums_2lctDSZ1l&q=85&s=748a1763454713e679260fbb95f154a2" style={{ width: "30%", minWidth: 60 }} width="621" height="1344" data-path="images/mastery-chain.png" />

  <img src="https://mintcdn.com/syntblazellc/-L0ums_2lctDSZ1l/images/element-previews.png?fit=max&auto=format&n=-L0ums_2lctDSZ1l&q=85&s=242f61448ff5dd6deaaab2dccc13b507" style={{ width: "30%", minWidth: 60 }} width="621" height="1344" data-path="images/element-previews.png" />

  <img src="https://mintcdn.com/syntblazellc/-L0ums_2lctDSZ1l/images/element-explanations.png?fit=max&auto=format&n=-L0ums_2lctDSZ1l&q=85&s=cf0fc1c31f9cd0fc26716781be05fbc9" style={{ width: "30%", minWidth: 60 }} width="621" height="1344" data-path="images/element-explanations.png" />
</div>
