> ## 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 Override Setter

In TypeScript, an override setter is a `set` accessor in a derived class annotated with the `override` keyword, explicitly declaring the intent to replace the assignment behavior of a property or setter inherited from a base class. When the `noImplicitOverride` compiler option is enabled in `tsconfig.json`, the compiler enforces a strict structural check, emitting an error if the base class does not possess a corresponding member to override.

```typescript theme={"dark"}
class Base {
    protected _count: number = 0;

    set count(value: number) {
        this._count = value;
    }
}

class Derived extends Base {
    override set count(value: number) {
        this._count = Math.max(0, value);
    }
}
```

## Technical Mechanics

**1. Target Resolution and Runtime Caveats**
An override setter can legally target and replace two types of base class members: an existing `set` accessor, or a standard class property.

Overriding a standard class property introduces a critical runtime caveat. If the `useDefineForClassFields` compiler option is enabled (which is the default for modern targets like `ES2022` and later), the base class initializes the property directly on the instance. This instance property will shadow the derived class's prototype accessors at runtime, meaning the setter will never be invoked when assigning to the property during or after base class instantiation.

```typescript theme={"dark"}
class BaseProperty {
    data: string = ""; // Initialized on the instance
}

class DerivedAccessor extends BaseProperty {
    private _data: string = "";
    
    override get data(): string {
        return this._data;
    }

    // Valid in TS, but fails at runtime if useDefineForClassFields is true.
    // The base instance property 'data' shadows this prototype setter.
    override set data(value: string) {
        this._data = value;
    }
}
```

**2. Type Compatibility and Contravariance**
To satisfy the Liskov Substitution Principle (LSP), the parameter type of the overriding setter must be contravariant. It must accept the exact type defined in the base class, or a wider (less specific) type. It cannot narrow the accepted type.

When widening a setter's parameter type, the property's read capability dictates TypeScript's structural checks:

* **Readable Properties:** If the base class defines a readable property (either as a standard property or via a `get` accessor), the derived class can widen the setter's parameter type as long as it explicitly provides a `get` accessor. This derived getter must return a type that is covariant (assignable) to the base class's read type.
* **Write-Only Properties:** If both the base and derived classes define only `set` accessors (omitting getters), the property is write-only. Write-only properties are strictly contravariant, meaning the derived setter can be widened without any covariant read-type checks.
* **Missing Read Contract:** If the base class defines a readable property but the derived class overrides *only* the setter, the derived property becomes write-only. This results in a compiler error because the derived class fails to fulfill the read contract required by the base class.

```typescript theme={"dark"}
class BaseType {
    // Base defines a standard readable property
    config: string | number = 0;
}

class DerivedType extends BaseType {
    private _config: string | number | boolean = 0;

    // Getter must be provided to satisfy the base class's covariant read contract
    override get config(): string | number { 
        return typeof this._config === "boolean" ? 0 : this._config; 
    }
    
    // Valid: Parameter type is wider (contravariant)
    override set config(value: string | number | boolean) { 
        this._config = value;
    }

    // Invalid: Parameter type is narrower. Will throw a compiler error.
    // override set config(value: string) { /* ... */ }
}
```

**3. Access Modifier Restrictions**
The overriding setter cannot enforce a stricter visibility modifier than the base class member. If the base setter is `public`, the override setter must remain `public`. If the base setter is `protected`, the override setter can remain `protected` or be widened to `public`.

**4. Getter/Setter Prototype Shadowing**
In JavaScript prototype chains, defining a setter on a derived prototype shadows the entire property descriptor of the base class. Consequently, overriding only the `set` accessor in the derived class does not automatically inherit the base `get` accessor. To maintain both read and write capabilities when extending behavior, the derived class must explicitly define both accessors, utilizing `super` calls if it needs to invoke the base class's accessor logic.

<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>
