TypeScript

TypeScript Getter Setter Errors: TS1056, TS2378, TS2380 Fix

TypeScript getter/setter errors come from ES target misconfiguration or type mismatches. Fix TS1056, TS1028, and TS2378 in minutes.

Mahdi Ben RhoumaMahdi Ben Rhouma
Updated
8 min read

These three codes are often searched together, but they have three different causes. TS1056 means the project targets ES3: accessors compile to Object.defineProperty, an ES5 feature, so the compiler refuses them below ES5. TS2378 means a getter has no return with a value. TS1028 ("Accessibility modifier already seen.") is not an accessor error at all: it fires when a member carries two visibility modifiers, such as public private get x().

On a current compiler, the ES3 target itself is gone: TypeScript 5.5 removed it, and TypeScript 6.0 deprecates ES5 too. The fix is therefore "target": "ES2015" or higher, not "ES5". Two more cases follow below: a getter that returns nothing, and a type mismatch between getter and setter on older compilers.

The errors#

You'll see one or more of these errors in your terminal or IDE when compiling or saving a file:

plaintext
 
error TS1056: Accessors are only available when targeting ECMAScript 5 and higher.
 
error TS1028: Accessibility modifier already seen.
 
error TS2378: A 'get' accessor must return a value.
 

It happens when you define a getter or setter inside a class, like this:

ts
 
class User {
 
  private _name = '';
 
  get name(): string {
 
    return this._name;
 
  }
 
  set name(value: string) {
 
    this._name = value;
 
  }
 
}
 

Here, private _name is a backing field, and the public name accessor pair is the only way callers read or write it. The backing field is initialised (= ''): under "strict": true, a field declared as private _name: string; with no initialiser and no constructor assignment fails with TS2564 before any accessor error appears.

Why it happens#

TypeScript's get and set accessors are syntactic sugar over JavaScript's Object.defineProperty — MDN documents its get/set accessor-descriptor keys as the standard mechanism for defining getter/setter pairs — which only works reliably in ES5 and later. If your tsconfig.json target compiler option is "ES3", the compiler refuses to emit accessor syntax and reports TS1056. The lib option plays no part: a project with "target": "ES2015" and "lib": ["ES2015"] compiles accessors without error.

Because the TypeScript 5.0 release notes deprecated --target ES3 and announced its removal in 5.5, a TypeScript 5.5+ compiler stops earlier, with error TS5108: Option 'target=ES3' has been removed. In practice TS1056 now appears only on TypeScript 5.4 or older.

ts
 
// src/types/user.ts
 
export class User {
 
  private _name = '';
 
  // On TypeScript 5.4 or older, this line triggers TS1056 if target is ES3
 
  get name(): string {
 
    return this._name;
 
  }
 
  set name(value: string) {
 
    this._name = value;
 
  }
 
}
 

Accessors in ambient contexts (.d.ts files and declare class blocks) are allowed. The TypeScript 3.6 release notes state that "users can write getters and setters in ambient contexts in TypeScript 3.6". Compilers up to 3.5 rejected them with a different code, TS1086: An accessor cannot be declared in an ambient context. This declaration compiles on any current version:

ts
 
// types/user.d.ts
 
declare class User {
 
  get name(): string;
 
  set name(value: string);
 
}
 

The fix — bump your ES target#

json
 
{
 
  "compilerOptions": {
 
    "target": "ES2015",
 
    "lib": ["ES2015", "DOM"],
 
    "outDir": "./dist",
 
    "rootDir": "./src"
 
  }
 
}
 

Any target of ES5 or later removes TS1056. ES2015 is the safer choice: the TypeScript 6.0 release notes deprecate target: es5 and make ES2015 the lowest target, and a TypeScript 7 compiler rejects "ES5" with TS5108.

Step by step#

  1. Open tsconfig.json.

  2. Locate the "compilerOptions" block.

  3. Add or update "target": "ES2015" (or "ES2020", "ES2022", etc.).

  4. Make "lib" match the target, or remove it to use the target's default.

  5. Save and restart your dev server (npm run dev) or re-run tsc.

If a .d.ts file with accessors must also be read by a TypeScript 3.5 or older consumer, declare a plain property instead (name: string;): that form is accepted by every version.

Confirm the compiler is reading your configuration#

If changing target appears to do nothing, check the command you run. The TypeScript configuration documentation states that passing input files on the command line ignores tsconfig.json. For example, npx tsc src/types/user.ts does not use the target you just edited in the project configuration.

Run these from your project directory:

bash
npx tsc --version
npx tsc --project tsconfig.json --showConfig
npx tsc --project tsconfig.json --noEmit

Check the resolved target in --showConfig, then look at the diagnostic from the project compile. Do not combine --project with an explicit input filename. In a monorepo, use the path to the package's own configuration. If only the editor reports the error, compare its selected TypeScript version with npx tsc --version before changing more compiler options.

DiagnosticCheck firstCorrective action
TS1056Old compiler plus an ES3 targetCompile the intended project with an ES2015 or higher target
TS5108 mentioning ES3Removed target optionRemove ES3 from the effective configuration, including inherited settings
TS2378Return belongs to a nested callbackReturn the result from the getter body
TS1028Two visibility modifiers on one memberKeep one of public, protected or private
TS2380Compiler version and accessor annotationsFollow the version-specific type rules below

For TS1028, public private get name() is invalid. Use public get name() or private get name() according to who should read the property; changing the compilation target cannot fix duplicate modifiers.

Check it#

bash
 
npx tsc --noEmit
 

Found 0 errors. — done. Still seeing errors? Two other variants:

Variant A — Getter returns undefined or void#

If the getter body contains no return with a value, you get TS2378, even when the getter is annotated : void. A frequent form is a return inside a callback, such as this.items.forEach((i) => { return i; }): that returns from the arrow function, not from the getter. A getter whose body only throws is accepted.

Fix by ensuring the getter returns a value matching the expected type:

ts
 
class Config {
 
  private _debug = false;
 
  get debug(): boolean {
 
    return this._debug; // ✅ Explicit return
 
  }
 
  set debug(value: boolean) {
 
    this._debug = value;
 
  }
 
}
 

Variant B — Setter parameter type mismatch#

A getter/setter type mismatch reports TS2380, not TS2378, and only on older compilers. TypeScript 4.2 and earlier required both to have the same type. TypeScript 4.3 to 5.0 required the getter's type to be assignable to the setter's. The TypeScript 5.1 release notes allow "completely unrelated types for get and set accessor properties, provided that they have explicit type annotations", so the commented-out setter below compiles without error on 5.1 and later.

On TypeScript 5.0 or older, fix by aligning types:

ts
 
class Temperature {
 
  private _celsius = 0;
 
  get celsius(): number {
 
    return this._celsius;
 
  }
 
  // TS2380 on TypeScript 5.0 or older; accepted from 5.1
 
  // set celsius(value: string) { this._celsius = parseFloat(value); }
 
  // ✅ Correct: both use number
 
  set celsius(value: number) {
 
    this._celsius = value;
 
  }
 
}
 

Preventing regressions#

Below ES5, TypeScript does not fall back to another accessor mechanism: it stops with TS1056. The check that catches a target regression is the compiler itself, so run tsc --noEmit in your CI pipeline; a lint rule such as @typescript-eslint/ban-ts-comment only governs @ts- comments and does not inspect the target.

For running tsc across a mixed JavaScript and TypeScript codebase while you convert it file by file, see JS to TypeScript: Incremental Migration, No Full Rewrite.

For deeper type safety, especially when working with Supabase or Next.js, see Complete Type Safety Guide for Next.js and Supabase with TypeScript.

Further reading: Fix "Property does not exist on Window" in TypeScript. Also see Fix Zod 4: errors Does Not Exist on ZodError.

Frequently Asked Questions

|

Have more questions? Contact us

Still stuck? Paste your error.

Paste the error message or stack trace — we check it against every fix and tool on the site.

Matching happens in your browser. When you search, a cleaned error signature is sent so we can spot errors we do not cover yet — never the raw text, your IP address or your e-mail. Do not paste passwords or keys. Details

Written by

Mahdi Ben Rhouma
Mahdi Ben Rhouma

Full-Stack Dev — Next.js & Supabase

Solo developer building SaaS products with Next.js and Supabase. Writing about production patterns the official docs skip.

Remote

One email a month — the latest explained errors

What the site published that month — mostly Next.js, Supabase and Node errors, explained. You confirm by email; unsubscribe any time in one click.