This TypeScript error occurs when decorators are used in unsupported locations, such as class expressions, anonymous classes, nested classes, or standalone functions. The fix involves moving decorators to supported declarations like top-level classes, methods, properties, or parameters.
The "Decorators are not valid here" error (TS1206) appears when you attempt to use a decorator in a syntactic context where TypeScript does not allow decorators. Decorators are special declarations that can modify classes, methods, accessors, properties, or parameters, but they have strict placement rules. TypeScript decorators must be attached to specific declaration types at the top level of their scope. They cannot be used with class expressions, classes nested inside objects, anonymous classes returned from functions, standalone functions, or interface/type definitions. This error commonly occurs when: 1. **Class expressions**: Attempting to decorate a class expression assigned to a variable or returned from a function 2. **Nested classes**: Using decorators on classes defined inside objects or other non-standard locations 3. **Anonymous classes**: Decorating classes in contexts like mixins where the class is anonymous 4. **Invalid targets**: Applying decorators to constructs that don't support them (functions, interfaces, types)
The most common cause is using decorators on class expressions. Convert them to proper class declarations:
// WRONG - decorator on class expression
const MyClass = @Component({
selector: 'app-root'
})
class { }
// Error: Decorators are not valid here
// CORRECT - decorator on class declaration
@Component({
selector: 'app-root'
})
class MyClass { }
// Or if you need the variable assignment
@Component({
selector: 'app-root'
})
class MyClassDeclaration { }
const MyClass = MyClassDeclaration;For exported classes:
// WRONG - class expression with decorator
export const AppComponent = @Component({
selector: 'app-root'
})
class { }
// CORRECT - declare class first, then export
@Component({
selector: 'app-root'
})
export class AppComponent { }Decorators cannot be used on classes nested inside objects or functions. Move them to module scope:
// WRONG - decorator on nested class
const services = {
UserService: @Injectable()
class {
getUser() { }
}
};
// Error: Decorators are not valid here
// CORRECT - extract to top level
@Injectable()
class UserService {
getUser() { }
}
const services = {
UserService
};For classes returned from functions:
// WRONG - decorator on anonymous returned class
function createService() {
return @Injectable()
class {
getData() { }
};
}
// CORRECT - declare class with name first
@Injectable()
class DataService {
getData() { }
}
function createService() {
return DataService;
}If you're using decorators in mixin patterns, refactor to apply decorators after class creation:
// WRONG - decorator on anonymous class in mixin
const TimestampMixin = (Base: any) => {
return @Entity()
class extends Base {
@Column()
createdAt: Date;
};
};
// Error: Decorators are not valid here on the inner class
// CORRECT - declare named class
const TimestampMixin = (Base: any) => {
@Entity()
class Timestamped extends Base {
@Column()
createdAt: Date;
}
return Timestamped;
};Alternative approach using a factory decorator:
// Apply decorator to the final composed class
function applyTimestamp<T extends { new(...args: any[]): {} }>(Base: T) {
return class extends Base {
createdAt: Date = new Date();
};
}
@Entity()
class User extends applyTimestamp(BaseEntity) {
@Column()
name: string;
}A common pattern that causes this error is exporting an instance of a decorated class:
// WRONG - decorator on instantiated class
export default new @Singleton()
class ApiClient {
@Log()
fetch() { }
}
// Error: Decorators are not valid here
// CORRECT - declare class separately, then instantiate
@Singleton()
class ApiClient {
@Log()
fetch() { }
}
export default new ApiClient();For singleton patterns:
// Declare decorated class
@Injectable()
class ConfigService {
private config: Config;
@Cache()
getConfig() {
return this.config;
}
}
// Export instance separately
export const configService = new ConfigService();If you're using legacy decorators (pre-TypeScript 5.0), ensure the compiler option is set:
// tsconfig.json
{
"compilerOptions": {
"experimentalDecorators": true,
"emitDecoratorMetadata": true // Often needed with DI frameworks
}
}For TypeScript 5.0+ with stage 3 decorators (no flag needed):
// tsconfig.json - stage 3 decorators work without flag
{
"compilerOptions": {
"target": "ES2022",
// experimentalDecorators is NOT needed for stage 3 decorators
}
}Note: If migrating from legacy to stage 3 decorators, syntax and behavior differ. Check your framework's documentation for compatibility.
Decorators can only be applied to specific targets. Ensure you're using them correctly:
// VALID decorator targets:
// 1. Class declarations
@Component()
class MyComponent { }
// 2. Class methods
class Service {
@Log()
fetchData() { }
}
// 3. Class properties
class User {
@Column()
name: string;
}
// 4. Method parameters
class Controller {
create(@Body() dto: CreateDto) { }
}
// 5. Accessors (getters/setters)
class Person {
@Validate()
get age() { return this._age; }
}// INVALID decorator targets:
// Standalone functions - NOT SUPPORTED
@Log() // Error
function fetchData() { }
// Interfaces - NOT SUPPORTED
@Entity() // Error
interface User { }
// Type aliases - NOT SUPPORTED
@Serializable() // Error
type Config = { };### Decorator Evaluation Order
When multiple decorators are applied to a single declaration, TypeScript evaluates them in a specific order:
Expression evaluation (top to bottom):
@first() // Evaluated first
@second() // Evaluated second
@third() // Evaluated third
class Example { }Function execution (bottom to top):
The decorator functions are called in reverse order: third() → second() → first()
Within a class:
1. Parameter decorators, then method/accessor/property decorators for each instance member
2. Parameter decorators, then method/accessor/property decorators for each static member
3. Parameter decorators for the constructor
4. Class decorators for the class
### Legacy vs Stage 3 Decorators
TypeScript supports two decorator implementations:
Legacy Decorators (experimentalDecorators)
Used by Angular, NestJS, TypeORM (pre-2024):
// tsconfig.json
{
"compilerOptions": {
"experimentalDecorators": true,
"emitDecoratorMetadata": true
}
}
// Decorator implementation
function Log(target: any, propertyKey: string) {
// Legacy decorator signature
}Stage 3 Decorators (TypeScript 5.0+)
ECMAScript standard decorators with different API:
// No compiler flag needed
// Decorator implementation
function Log(target: Function, context: ClassMethodDecoratorContext) {
// Stage 3 decorator signature
}These are NOT compatible. If you see "Decorators are not valid here" after upgrading TypeScript, your framework may need to update for stage 3 support.
### Decorator Factories
To create configurable decorators, use decorator factories (functions that return decorators):
// Decorator factory
function Component(config: { selector: string }) {
return function (target: Function) {
// Actual decorator logic
target.prototype.selector = config.selector;
};
}
// Usage - note the function call ()
@Component({ selector: 'app-root' })
class AppComponent { }The @Component({ selector: 'app-root' }) syntax is actually:
1. Call Component() → returns a decorator function
2. Apply that decorator to the class
### Reflect Metadata API
Many decorator-based frameworks use metadata reflection:
import 'reflect-metadata';
function Type(type: any) {
return Reflect.metadata('design:type', type);
}
class User {
@Type(String)
name: string;
}
// Read metadata at runtime
const type = Reflect.getMetadata('design:type', User.prototype, 'name');
console.log(type); // [Function: String]Requires emitDecoratorMetadata: true and reflect-metadata package.
### Framework-Specific Patterns
Angular
// WRONG
export const AppComponent = @Component({ ... }) class { };
// CORRECT
@Component({ ... })
export class AppComponent { }NestJS
// WRONG
const UserController = @Controller('users') class { };
// CORRECT
@Controller('users')
export class UserController { }TypeORM
// WRONG
const UserEntity = @Entity() class { };
// CORRECT
@Entity()
export class User { }### Debugging Decorator Issues
Enable verbose compiler output to see exactly where decorators are being applied:
npx tsc --listEmittedFiles --listFilesCheck the emitted JavaScript to verify decorator transformation:
npx tsc --declaration --emitDecoratorMetadata
cat dist/your-file.jsFunction expression requires a return type
Function expression requires a return type
Value of type 'string | undefined' is not iterable
How to fix "Value is not iterable" in TypeScript
Type 'undefined' is not assignable to type 'string'
How to fix "Type undefined is not assignable to type string" in TypeScript
Type narrowing from typeof check produces 'never'
How to fix "Type narrowing produces never" in TypeScript
Type parameter 'T' has conflicting constraints
How to fix "Type parameter has conflicting constraints" in TypeScript