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.
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:
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:
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.
// 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:
// types/user.d.ts
declare class User {
get name(): string;
set name(value: string);
}
The fix — bump your ES target#
{
"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#
-
Open
tsconfig.json. -
Locate the
"compilerOptions"block. -
Add or update
"target": "ES2015"(or"ES2020","ES2022", etc.). -
Make
"lib"match the target, or remove it to use the target's default. -
Save and restart your dev server (
npm run dev) or re-runtsc.
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:
npx tsc --version
npx tsc --project tsconfig.json --showConfig
npx tsc --project tsconfig.json --noEmitCheck 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.
| Diagnostic | Check first | Corrective action |
|---|---|---|
| TS1056 | Old compiler plus an ES3 target | Compile the intended project with an ES2015 or higher target |
| TS5108 mentioning ES3 | Removed target option | Remove ES3 from the effective configuration, including inherited settings |
| TS2378 | Return belongs to a nested callback | Return the result from the getter body |
| TS1028 | Two visibility modifiers on one member | Keep one of public, protected or private |
| TS2380 | Compiler version and accessor annotations | Follow 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#
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:
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:
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
Still stuck? Paste your error.
Paste the error message or stack trace — we check it against every fix and tool on the site.
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.
Continue Reading
Fix "Property does not exist on Window" in TypeScript
Learn how to safely extend the Window interface in TypeScript with declaration merging and declare global, and why bracket notation on an undeclared key fails under noImplicitAny.
Fix Zod 4: errors Does Not Exist on ZodError
Repair the missing errors property without losing nested paths, hiding validation failures or turning unexpected exceptions into form errors.
Fix Cannot find name 'console' in TypeScript (TS2584)
console.log fails to type-check in a Node project. See which two tsconfig settings hide console, why the compiler hint points the wrong way, and the fix.


