A Set Accessor Cannot Have A Return Type Annotation | Fix Error

The TypeScript message “a set accessor cannot have a return type annotation” means setter methods must not declare a return type and always act as void.

When this compiler error pops up, it often interrupts a clean refactor or a strict linting pass that asks for return types everywhere. On the surface it looks odd, because TypeScript encourages explicit types in almost every corner of a codebase. This guide walks through why the rule exists, how the language treats getters and setters, and the exact changes you can apply so the error disappears without weakening your types.

You will see the message in editors that use TypeScript under the hood, flagged as error code TS1095. It appears in both classes and interfaces, and it can also collide with rules from @typescript-eslint that request explicit return types for functions. Once you understand the intended shape of an accessor, the fix turns into a quick edit instead of a frustrating guessing game.

What Does “A Set Accessor Cannot Have A Return Type Annotation” Mean?

In TypeScript, an accessor pair gives a property a getter, a setter, or both. A getter returns a value, so it may and often should declare a return type. A setter only receives a value and updates some internal field; it does not return anything. Because of that design, a setter in TypeScript always behaves as if it returns void.

The message a set accessor cannot have a return type annotation shows up when you write a setter that looks like a function with a typed return, such as set name(value: string): string. The compiler rejects that shape even when the type you write is void. The rule is strict: no return type annotation is allowed on a set accessor at all, even when the annotation matches the internal behavior.

A getter and setter pair for the same property may use different types, and TypeScript has dedicated inference rules for the parameter type on the setter. The setter parameter type is either declared directly or inferred from the getter return type when both exist. This design removes any need to declare a return type on the setter, since the compiler already knows what flows in and assumes nothing comes out.

Set Accessor Return Type Annotation Error In TypeScript

The core rule comes straight from the language specification and long-standing behavior in the compiler. A setter may contain an expressionless return; to short-circuit on validation, yet it still has an effective return type of void. Tooling discussions around this error confirm that the actual problem is the annotation on the setter signature, not the presence of an empty return statement.

Here is a minimal example that triggers TS1095:


class Person {
  private _name = "";

  set name(value: string): string { // <-- TS1095 here
    if (value.length === 0) {
      throw new Error("Name must not be empty.");
    }
    this._name = value;
  }

  get name(): string {
    return this._name;
  }
}
  

The setter signature ends with : string. The compiler sees that annotation and raises “a set accessor cannot have a return type annotation” even though the body never returns a value. Removing : string resolves the error. The getter keeps its return type; only the setter needs the adjustment.

The same thing happens inside an interface or a type with accessor syntax. When a project uses strict lint rules that demand explicit return types, this creates tension between the linter and the compiler. The linter requests a type annotation, while TypeScript reports an error as soon as you add one to the setter.

Common Code Patterns That Trigger The Error

The message often shows up in a few recurring patterns. Once you recognize them, you can spot the issue as soon as the code formatter adds a stray type.

Setter With An Explicit Non-Void Return Type


class Account {
  private _balance = 0;

  set balance(value: number): number { // TS1095
    if (value < 0) {
      throw new Error("Balance cannot be negative.");
    }
    this._balance = value;
    return this._balance;
  }
}
  
  • Wrong shape for a setter — The code tries to use the setter like a method by returning the updated value. In TypeScript, a setter never advertises a return type and should not return a value.

Setter Annotated With Void


class SettingsStore {
  private _theme = "light";

  set theme(value: string): void { // TS1095 again
    this._theme = value;
  }
}
  
  • Annotation still forbidden — Even though void matches the intent, the language rule still prohibits a return type annotation. The compiler knows the setter behaves like a void function without needing that note.

Interface With A Setter And Return Type


interface UserProfile {
  get email(): string;
  set email(value: string): boolean; // TS1095
}
  
  • Accessors inside interfaces — The error appears inside interfaces too. The setter signature cannot declare boolean as a return type, even though it might look like a convenient hook for validation feedback.

How To Fix A Set Accessor Cannot Have A Return Type Annotation

The fix always centers on the setter signature. You leave or add types where they are valid and remove them where the compiler does not allow them. The goal is a setter that expresses its parameter type clearly and omits any return type annotation.

  1. Remove The Return Type Annotation — Edit the setter signature and delete the : Type part after the parameter list, even when that type is void.
  2. Keep Or Add A Parameter Type — Ensure the parameter inside the setter has an explicit type, or rely on inference from the getter if both exist.
  3. Return Nothing From The Setter — Remove any return someValue; lines and keep only plain return; if you need an early exit.
  4. Adjust Lint Rules If Needed — Update explicit-function-return-type or similar rules so they skip accessors and stop requesting a return type where TypeScript bans it.

Before And After Fix


// Before
class Temperature {
  private _celsius = 0;

  set celsius(value: number): void { // TS1095
    if (value < -273.15) {
      throw new Error("Below absolute zero.");
    }
    this._celsius = value;
  }

  get celsius(): number {
    return this._celsius;
  }
}

// After
class Temperature {
  private _celsius = 0;

  set celsius(value: number) { // no return type here
    if (value < -273.15) {
      throw new Error("Below absolute zero.");
    }
    this._celsius = value;
  }

  get celsius(): number {
    return this._celsius;
  }
}
  

In the fixed version the setter parameter keeps its explicit number type while the return type annotation disappears. The getter still returns number, which keeps call sites well typed. The error “a set accessor cannot have a return type annotation” no longer appears.

Keeping Linters And The Compiler In Sync

Many teams enable rules from @typescript-eslint that insist on explicit return types for functions. Without any extra configuration those rules may also apply to getters and setters. When that happens, the linter pushes you toward adding : void on the setter, and then the compiler rejects that change.

  • Update Explicit Return Type Rules — Configure explicit-function-return-type or a similar rule to ignore accessors or treat them as a special case so the rule no longer asks for a return type on setters.
  • Run TypeScript As The Source Of Truth — If a linter rule disagrees with the compiler, adjust the rule rather than work around TypeScript by changing accessor patterns.

Best Practices For Get And Set Accessors In TypeScript

Once the error is out of the way, it helps to settle on a consistent accessor style for a project. Clear, predictable rules for getters and setters reduce friction when people move across files or when tooling formats your code automatically.

Keep Getters And Setters Simple

  • Avoid Heavy Logic In Accessors — Use simple validation and assignment inside setters, and delegate complex workflows to separate methods so property access stays easy to reason about.
  • Prefer One Responsibility Per Accessor — A getter should read state and a setter should update it. When an operation performs more than that, consider a named method instead of an accessor.

Match Getter Return Types And Setter Parameter Types

  • Align Types For The Same Property — When both accessor forms exist for a property, return the same type in the getter that you accept in the setter, unless you have a clear reason to differ.
  • Let Inference Help When Appropriate — TypeScript infers the setter parameter type from the getter return type when you omit it, which can reduce repetition while keeping behavior predictable.

Use Accessors Where They Add Clarity

  • Reserve Accessors For Property-Like Usage — Choose getters and setters when callers should treat a value as a field. If the action reads like a verb, a normal method often expresses intent better.
  • Document Validation Behavior — When a setter throws or clamps values, add short comments or JSDoc so callers understand the contract without digging through implementations.

With these habits in place, a project can rely on accessors without surprises. The rule that a set accessor cannot have a return type annotation then feels less like an arbitrary restriction and more like a reflection of well-shaped property access.

How To Fix A Set Accessor Cannot Have A Return Type Annotation In Larger Codebases

In a small example file, removing a single return type annotation is quick. In a large codebase with hundreds of classes, the error may show up in many places at once after a TypeScript upgrade or linter change. In that setting it helps to handle the problem in a structured run rather than one file at a time.

  • Search For Setter Signatures With Return Types — Use your editor or command-line tools to search patterns like set followed by ): so you can review all accessors with return type annotations.
  • Batch Remove Return Type Annotations — Once you confirm the pattern, apply multi-file edits that strip the return type from setters while keeping parameter types intact.
  • Re-run TypeScript And Linters — After bulk edits, run the compiler and lint suite to catch any missed cases and to verify that linter configuration no longer requests return types for setters.

During that process, you may turn up legacy patterns where setters were used like fluent APIs that return this or some other value. Refactoring those into explicit methods can clean up call sites and align the code with TypeScript’s accessor expectations at the same time.

Quick Reference For Set Accessor Rules

The table below condenses the main rules that relate to setters and their types so you can scan them when a similar error appears again.

Pattern Allowed? Notes
set value(v: T): U { ... } No Setter cannot declare a return type; remove : U and stop returning a value.
set value(v: T): void { ... } No Even void as a return type annotation triggers “a set accessor cannot have a return type annotation”.
set value(v: T) { return; } Yes Expressionless return; is fine; return type is still treated as void without annotation.
get value(): T { ... } Yes Getters may and often should declare a return type; they are regular value-returning functions.
Setter inside interface with return type No Interfaces follow the same rule as classes; omit return type annotations on setters there too.
Setter parameter without explicit type Depends TypeScript infers the setter parameter type from the getter when both exist; otherwise add an explicit parameter type.

When you see “a set accessor cannot have a return type annotation” again, look directly at the setter signature. If you spot any : Type after the parameter list, that is almost always the source of the problem. Remove that part, keep the parameter types and getter types solid, and the compiler will be satisfied while your code stays strongly typed.