Question
Understanding the Experimental Decorators Warning in TypeScript
Question
I am getting this TypeScript warning:
Experimental support for decorators is a feature that is subject to change in a future release. Set the 'experimentalDecorators' option to remove this warning.
However, my tsconfig.json already includes:
{
"compilerOptions": {
"emitDecoratorMetadata": true,
"experimentalDecorators": true
}
}
What is confusing is that some classes using decorators in the same project do not show the warning, while many others do.
What can cause this inconsistent behavior in the TypeScript compiler?
Short Answer
By the end of this page, you will understand what the experimentalDecorators warning means in TypeScript, why it can still appear even when the option is enabled, and how to troubleshoot configuration, tooling, and project-structure issues that cause inconsistent behavior.
Concept
Decorators in TypeScript are a language feature that must be explicitly enabled. The experimentalDecorators compiler option tells TypeScript that your project intentionally uses decorators.
If that option is enabled and you still see the warning, the most important idea is this:
- the file may not actually be compiled with the
tsconfig.jsonyou think it is - a different tool may be compiling the file
- the editor may be using a different TypeScript project context
- some files may belong to another
tsconfig.jsonor no project at all
In real projects, TypeScript code is often handled by more than one system:
- the TypeScript compiler (
tsc) - your editor's TypeScript language service
- a bundler such as Webpack, Vite, or esbuild
- a test runner
- Babel or another transpiler
That means one part of your setup may respect experimentalDecorators, while another part may ignore it or use a different config.
This matters because many TypeScript problems are not caused by syntax errors. They are caused by configuration scope: which files are included, which config is active, and which tool is reading it.
Mental Model
Think of tsconfig.json like a rulebook for a classroom.
You assume every student is following the same rulebook, but in reality:
- some students are in a different classroom
- some are using last week's rulebook
- some are being taught by a substitute teacher
Decorators warnings often happen for the same reason. You enabled the rule in one tsconfig.json, but some files are being checked under a different rulebook.
So the question is usually not "Did I set experimentalDecorators?" but "Which config is this file actually using?"
Syntax and Examples
The relevant TypeScript configuration looks like this:
{
"compilerOptions": {
"experimentalDecorators": true,
"emitDecoratorMetadata": true
}
}
A simple decorator example:
function sealed(constructor: Function) {
Object.seal(constructor);
Object.seal(constructor.prototype);
}
@sealed
class UserService {
getUser() {
return "Alice";
}
}
What these options do
experimentalDecorators: true- Allows decorator syntax like
@sealed
- Allows decorator syntax like
emitDecoratorMetadata: true- Emits extra metadata for reflection-based libraries such as Angular or NestJS
- This does not enable decorators by itself
That means this is not enough:
{
"compilerOptions": {
"emitDecoratorMetadata": true
}
}
You still need:
{
"compilerOptions": {
"experimentalDecorators": true
}
}
Common hidden issue
A project may contain multiple config files:
tsconfig.json
tsconfig.app.json
tsconfig.spec.json
If one file is compiled using tsconfig.app.json and another is checked using tsconfig.spec.json, their behavior can differ if those configs do not all inherit the same decorator settings.
Step by Step Execution
Consider this project structure:
project/
tsconfig.json
src/
app.ts
scripts/
generate.ts
And this tsconfig.json:
{
"compilerOptions": {
"experimentalDecorators": true
},
"include": ["src/**/*"]
}
Now imagine these files:
// src/app.ts
function logClass(target: Function) {}
@logClass
class App {}
// scripts/generate.ts
function logClass(target: Function) {}
@logClass
class Generator {}
What happens
- TypeScript reads
tsconfig.json. - The
includefield only includessrc/**/*. src/app.tsis part of the project, so it gets checked withexperimentalDecorators: true.scripts/generate.tsis not part of the project.- Your editor may treat
scripts/generate.tsas an isolated file or part of another inferred project. - Since that inferred project does not use your intended config, the decorator warning appears there.
This explains why some files show the warning and some do not, even in the same repository.
Another common path
- You open a TypeScript file in your editor.
- The editor's TypeScript server decides which
tsconfig.jsonapplies. - If no matching config includes the file, it falls back to a default project.
- Default settings do not necessarily enable decorators.
- The warning appears in the editor, even if
tscfrom the terminal behaves differently.
Real World Use Cases
Decorators are commonly used in frameworks and libraries that attach metadata or modify behavior.
Common examples
- Angular
@Component,@Injectable,@Directive
- NestJS
@Controller,@Get,@Injectable
- TypeORM
@Entity,@Column,@PrimaryGeneratedColumn
- Custom app infrastructure
- logging decorators
- validation decorators
- permission decorators
- caching decorators
Why the warning matters in practice
If one part of your app compiles with decorators enabled and another does not:
- builds may fail only in certain environments
- editors may show warnings that CI does not
- test files may behave differently from app files
- generated metadata may be missing in one part of the system
This is especially common in monorepos, apps with multiple tsconfig files, and projects using both Babel and TypeScript.
Real Codebase Usage
In real codebases, developers usually solve this by making configuration explicit and shared.
Common patterns
1. Base config inheritance
Create a shared base config:
{
"compilerOptions": {
"experimentalDecorators": true,
"emitDecoratorMetadata": true
}
}
Then extend it:
{
"extends": "./tsconfig.base.json",
"compilerOptions": {
"outDir": "dist"
},
"include": ["src/**/*"]
}
This avoids one config accidentally missing decorator support.
2. Separate app and test configs
Projects often have:
tsconfig.app.jsontsconfig.spec.jsontsconfig.node.json
Each one should either define or inherit the same decorator settings if those files use decorators.
3. Validate which config is active
A very useful command is:
tsc --showConfig
This shows the final resolved config after extends is applied.
You can also compile a specific project file:
tsc -p tsconfig.json
4. Guard against editor mismatch
Sometimes the terminal build is correct, but the editor still warns. In that case developers often:
- restart the TypeScript server
- confirm the editor is using the workspace TypeScript version
- confirm the file belongs to the expected project
5. Toolchain consistency
If Babel, Jest, ts-node, or a bundler is involved, make sure that tool also supports decorators and is using the expected configuration.
Common Mistakes
1. Assuming emitDecoratorMetadata enables decorators
Broken assumption:
{
"compilerOptions": {
"emitDecoratorMetadata": true
}
}
Why it fails:
emitDecoratorMetadataonly adds metadata- it does not allow
@decoratorsyntax
Fix:
{
"compilerOptions": {
"experimentalDecorators": true,
"emitDecoratorMetadata": true
}
}
2. File is outside the include pattern
Broken config:
{
"compilerOptions": {
"experimentalDecorators": true
},
"include": ["src/**/*"]
}
If your decorated file is in tools/ or scripts/, it may not be using this config.
Fix:
{
"include": ["src/**/*", "scripts/**/*", "tools/**/*"]
}
3. Multiple tsconfig files with different settings
For example:
// tsconfig.app.json
{
"compilerOptions": {
"experimentalDecorators": true
}
}
// tsconfig.spec.json
{
"compilerOptions": {}
}
Now app files may work while test files warn.
Fix:
- use a shared base config
- or copy the needed setting into all relevant configs
4. Editor uses a different TypeScript version
Some editors bundle their own TypeScript version.
This can lead to:
- different warnings
- stale diagnostics
- config resolution differences
Fix:
- switch to the workspace TypeScript version
- restart the editor TypeScript service
5. Babel or another tool is handling decorators separately
If you compile through Babel, TypeScript settings may not be the only source of truth.
Fix:
- verify Babel decorator support is enabled if Babel is transforming the code
- make sure the TypeScript and Babel setups are compatible
6. Opening a single file outside project context
If you open a file directly, the editor may treat it as an isolated file instead of part of your configured project.
Fix:
- open the project root folder
- ensure the file is included by a
tsconfig.json - check editor project diagnostics
Comparisons
| Situation | What it means | Typical result |
|---|---|---|
experimentalDecorators: true | Decorator syntax is allowed | @MyDecorator compiles |
emitDecoratorMetadata: true only | Metadata emission requested, but decorators not enabled | Warning or compile error for decorators |
File included in active tsconfig.json | File uses project compiler options | Consistent behavior |
File not included in active tsconfig.json | File may be in inferred project | Warning may appear unexpectedly |
Terminal tsc works, editor warns | Editor is using different project/config/version | Inconsistent diagnostics |
One tsconfig extends another | Shared compiler settings possible | Easier consistency |
Multiple unrelated tsconfig files | Different settings per subproject | Some files warn, others do not |
experimentalDecorators vs emitDecoratorMetadata
| Option | Purpose | Required for decorator syntax? |
|---|---|---|
experimentalDecorators | Enables decorator syntax | Yes |
emitDecoratorMetadata | Emits runtime design metadata | No |
tsc vs editor diagnostics
| Tool | Reads config? | Can differ? |
|---|---|---|
tsc -p tsconfig.json | Yes | Usually predictable |
| Editor TypeScript service | Yes, but based on detected project | Yes |
| Babel | Not based on tsconfig alone | Yes |
Cheat Sheet
{
"compilerOptions": {
"experimentalDecorators": true,
"emitDecoratorMetadata": true
}
}
Quick rules
experimentalDecoratorsenables decorator syntaxemitDecoratorMetadatadoes not enable decorators by itself- a file must belong to the correct TypeScript project to get those settings
- multiple
tsconfigfiles can cause inconsistent behavior - editor warnings may differ from terminal builds
Useful checks
tsc --showConfig
tsc -p tsconfig.json
Things to inspect
- Is the file inside
include? - Is the file excluded?
- Is there another
tsconfigcloser to that file? - Does the project use
extends? - Is the editor using workspace TypeScript?
- Is Babel, ts-node, or a bundler compiling the file instead?
Most likely causes of inconsistent warnings
- file not included in the expected
tsconfig - multiple
tsconfigfiles with different options - editor TypeScript service using a different project
- different toolchain for different folders or file types
FAQ
Why do I get the decorators warning even though experimentalDecorators is true?
Usually because the file is not being compiled with the tsconfig.json you edited, or your editor is using a different TypeScript project context.
Why do only some files show the warning in the same project?
Those files may belong to a different tsconfig, be outside the include pattern, or be treated as inferred standalone files by the editor.
Does emitDecoratorMetadata enable decorators in TypeScript?
No. It only emits additional metadata. You still need experimentalDecorators: true.
How can I check which TypeScript config is being used?
Use tsc --showConfig for the active project config, and check your editor's TypeScript project information if available.
Can the problem come from my editor rather than the compiler?
Yes. Editors often run their own TypeScript language service, which can use a different TypeScript version or detect a different project.
Can multiple tsconfig.json files cause this issue?
Yes. This is one of the most common reasons for inconsistent decorator warnings.
Should I restart the TypeScript server after changing tsconfig.json?
Yes. Some editors cache project state, so restarting the TypeScript service can clear stale warnings.
Mini Project
Description
Build a small TypeScript project with two folders to demonstrate why one decorated file can work while another shows warnings. This helps you understand that compiler options only apply to files that belong to the active TypeScript project.
Goal
Create a project where src files support decorators, then fix configuration so scripts files support them too.
Requirements
- Create a
tsconfig.jsonthat enablesexperimentalDecorators. - Include only the
srcfolder at first. - Add one decorated class in
srcand one inscripts. - Update the config so both folders use the same decorator settings.
- Verify the final setup compiles consistently.
Keep learning
Related questions
@Directive vs @Component in Angular: Differences, Use Cases, and When to Use Each
Learn the difference between @Directive and @Component in Angular, including use cases, examples, and when to choose each.
Accessing Input Value from EventTarget in TypeScript
Learn why EventTarget has no value property in TypeScript and safely read values from HTML input events in Angular applications.
Angular (change) vs (ngModelChange): What’s the Difference?
Learn the difference between Angular (change) and (ngModelChange), when each fires, and which one to use in forms and inputs.