Enums define a set of named constants that compile to either numeric reverse-mapped objects or plain constants
Regular enums generate a runtime object with reverse mapping, doubling bundle size for consumer code
const enums are completely inlined at compile time — zero runtime overhead, but break when used with isolatedModules
Decorators are functions applied with @ syntax that run at class definition time; order matters
The reflect-metadata polyfill is required for decorator metadata — missing it causes silent failures
Biggest mistake: assuming const enums can be consumed across packages without a companion .d.ts
✦ Definition~90s read
What is TypeScript Enums and Decorators?
TypeScript enums are a language feature that lets you define a set of named constants, but they're not just syntactic sugar—they compile to real JavaScript objects with a bidirectional mapping (reverse mapping) by default. This means a regular enum like enum Color { Red, Green, Blue } generates an object where you can look up Color.Red (0) and Color[0] ('Red').
★
Imagine a traffic light.
That reverse mapping is what bloats your bundle: a simple enum with 3 values can add ~12KB of minified JavaScript because the emitted code includes a runtime object with both key-to-value and value-to-key mappings. For production apps, this is often unnecessary overhead—you're paying for a feature you might not use, especially if you only need forward lookups or just the numeric values.
Const enums exist to solve this: they're inlined at compile time, producing zero runtime code. But they come with trade-offs—you can't use them with --isolatedModules (common in Babel/Next.js setups) because they require full type information during compilation.
Regular enums also interact poorly with decorators and metadata reflection: since enums compile to mutable objects, decorators that read or modify enum metadata at runtime can trigger unexpected side effects or execution order issues. The reflect-metadata polyfill, often used with decorators, adds another layer of complexity—it stores type metadata as strings, and enum reverse mappings can cause circular references or inflated serialization.
In the ecosystem, enums compete with union types (type Color = 'Red' | 'Green' | 'Blue') and string literal unions, which compile to nothing and are safer for bundle size. If you're using a framework like Angular (which relies heavily on decorators and metadata reflection), regular enums can silently increase your initial payload.
The rule of thumb: use const enums for internal code where you control the build pipeline, prefer union types for public APIs or library code, and avoid regular enums in hot paths or decorator-heavy modules unless you explicitly need reverse mapping at runtime.
Plain-English First
Imagine a traffic light. It can only ever be red, yellow, or green — not 'purple' or 42. An enum is exactly that: a named set of allowed values so your code can never accidentally use an invalid one. A decorator is like a sticky note you put on a function or class that says 'hey, before you run this, also do THIS' — the way a hotel doorman checks your key card before letting you into a room, without you having to write that check inside every room.
⚙ Browser compatibility
Latest versions — ✓ supported
Chrome
Firefox
Safari
Edge
✓
✓
✓
✓
TypeScript enums and decorators sit at opposite ends of the language's complexity spectrum — one is deceptively simple, the other is genuinely advanced — but production codebases constantly misuse both. Enums end up bloating your bundle because developers don't understand how they compile. Decorators get cargo-culted from Angular or NestJS without anyone understanding the metadata system underneath. Both mistakes are expensive and embarrassing in a code review.
Enums exist because magic strings and magic numbers are silent killers. When your REST API returns status code 3 and your switch statement handles 1, 2, and 4, nothing explodes — the wrong branch just quietly runs forever. Decorators exist because cross-cutting concerns — logging, validation, authorization, caching — don't belong inside your business logic, and the alternative (manually wrapping every method) doesn't scale. Both features are TypeScript's answer to 'how do we write large, team-maintained codebases without losing our minds?'
By the end of this article you'll understand exactly what JavaScript TypeScript emits for each enum variant, when a const enum will save your bundle and when it will burn you, how decorators hook into ES2022's reflect-metadata system, how to write a production-grade method decorator from scratch, and the three mistakes that trip up even experienced engineers. You'll also have answers ready for the interview questions that separate senior candidates from mid-level ones.
What TypeScript Enums Actually Compile To
TypeScript enums are a language construct that maps a set of named constants to numeric or string values. Unlike most TypeScript features, enums are not just a type-level abstraction — they emit real JavaScript objects at runtime. A numeric enum generates a bidirectional mapping: both name→value and value→name. This reverse mapping is the core mechanic that distinguishes enums from simple const objects or union types.
When you write enum Status { Active = 1, Inactive = 2 }, TypeScript compiles it to an object with properties { 1: 'Active', 2: 'Inactive', Active: 1, Inactive: 2 }. This means every numeric enum doubles the number of emitted object properties. For string enums, reverse mapping is not generated — only name→value. The entire enum object is inlined into every module that imports it, which can cause significant bundle bloat when enums are large or widely used.
Use enums when you need runtime iteration over all values (e.g., Object.values(Status)) or when you must map from a numeric value back to its name, such as when deserializing API responses. For all other cases — especially in library code or performance-critical bundles — prefer const enum (which inlines values with no runtime object) or a plain union of string literals. The choice directly impacts bundle size: a 12KB enum object in a shared module can balloon a tree-shaken bundle because the entire object is retained.
⚠ Reverse Mapping Is Always Emitted
Even if you never use reverse mapping, TypeScript still generates it for numeric enums. This is not tree-shakeable — the full object stays in the bundle.
📊 Production Insight
A payment service used a numeric enum with 200 status codes in a shared library. The enum compiled to a 12KB object that was imported by 40 microservices. After migrating to a const object with union types, the bundle per service dropped by 8KB, reducing cold-start latency by 15%.
The exact symptom: webpack bundle analyzer showed a single module contributing 12KB that could not be tree-shaken — every import of the enum pulled the entire reverse mapping.
Rule of thumb: if you don't need runtime name→value lookup, use a const object with as const and a union type. That compiles to zero runtime code.
🎯 Key Takeaway
Numeric enums emit a bidirectional object at runtime — every value gets both a name and a reverse key.
String enums emit only forward mapping, making them safer for bundle size.
For zero-cost enums, use const enum or a union of string literals with as const.
thecodeforge.io
Typescript Enums Decorators
How TypeScript Enums Compile to JavaScript
Understanding the compiled output of enums is critical for making the right choice between regular, const, and string enums. When you write enum Status { Active, Inactive }, TypeScript outputs something like:
This is an IIFE that builds an object with both forward (Status.Active → 0) and reverse (Status[0] → "Active") mappings. The reverse mapping is a feature that allows you to get the string name from a numeric value. However, it also means the entire enum object is a side effect — bundlers like Webpack or Rollup treat this as unsafe for tree-shaking, so even if you only use Status.Active, the whole object stays in the bundle.
Const enums are different. They're completely removed at compile time and replaced with literal values. const enum Status { Active = 0 } becomes just 0 wherever Status.Active is used. This gives zero runtime overhead but breaks when the enum is exported across module boundaries and isolatedModules is enabled. In that case, TypeScript warns with TS2748: Cannot access ambient const enums when 'isolatedModules' is enabled.
String enums (enum Status { Active = 'ACTIVE' }) compile to an IIFE as well, but without reverse mapping because string values can't be reversed uniquely (the compiler doesn't generate Status["ACTIVE"] = "ACTIVE"). They're safer for library exports but still carry the IIFE overhead.
enums-compile-examples.tsTYPESCRIPT
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
// Regular enum — has reverse mappingenumHttpStatus { OK = 200, NotFound = 404 }
// Compiled output includes IIFE// var HttpStatus;// (function (HttpStatus) {// HttpStatus[HttpStatus["OK"] = 200] = "OK";// HttpStatus[HttpStatus["NotFound"] = 404] = "NotFound";// })(HttpStatus || (HttpStatus = {}));// Const enum — inlined at usageconstenumDirection { Up = 'UP', Down = 'DOWN' }
let move = Direction.Up; // compiles to 'UP'// String enum — no reverse mappingenumColor { Red = 'RED', Green = 'GREEN' }
// Only forward mapping emitted
Think of a regular enum as a dictionary that lets you go from key to value AND from value to key.
Forward mapping: Status.Active → 0
Reverse mapping: Status[0] → "Active"
Const enums lose the reverse mapping but gain zero-cost lookup.
String enums only have forward mapping — no reverse.
The IIFE wrapper is a side effect that prevents tree-shaking, even if only one key is used.
📊 Production Insight
A shared library with 3 regular enums added 8KB to the final bundle — every consumer paid that tax.
Switching to const enums with preserveConstEnums: true removed the IIFE but kept the .d.ts for consumers.
Rule: Never export a regular enum from an npm package; prefer const enum or union types.
🎯 Key Takeaway
Regular enums generate an IIFE with reverse mapping; const enums inline at zero cost.
The IIFE is a side effect that bundlers can't tree-shake.
Use const enums for internal use and union types or as const objects for public APIs.
Const Enums vs Regular Enums: Production Trade-offs
The choice between regular and const enums is a trade-off between developer experience and bundle size. Here's the decision framework:
Regular enums** are good when
You need reverse mapping (e.g., converting a numeric API response to a readable label).
You're in a codebase that doesn't use a bundler or uses tsc alone.
You want the enum to be iterable (e.g., for generating UI options).
Const enums** are good when
You control the build pipeline and can disable isolatedModules.
The enum values are never used in reflection or comparison with other enums.
You're writing a library that you want consumers to tree-shake aggressively.
But beware: const enums have a hidden cost. When exported from a library and consumed in a project with isolatedModules: true, they become ambient — meaning you can't access them at runtime. The fix is to add preserveConstEnums: true in your library's tsconfig, which will emit a regular enum alongside the const enum so consumers can use it. But then you lose the bundle savings.
An alternative that many senior engineers use: skip enums entirely and use as const objects with union types. This gives you compile-time safety, no runtime overhead, and great IDE support — at the cost of slightly more verbose syntax.
📊 Production Insight
A team migrated an Angular app from regular enums to as const objects and saved 34KB in production bundle.
The refactor took 2 hours but removed all IIFE overhead and made tree-shaking effective.
Rule: For new code, prefer as const over enums — you get the same type safety with less runtime cost.
🎯 Key Takeaway
Const enums eliminate runtime overhead but break across modules with isolatedModules.
Regular enums provide reverse mapping and module safety at the cost of bundle size.
The modern preference is as const — same safety, zero IIFE, full tree-shakability.
thecodeforge.io
Typescript Enums Decorators
Decorator Syntax and Execution Order
Decorators in TypeScript are functions that receive the decorated element and can modify it. There are four types: class decorators, method decorators, accessor decorators, and property decorators. Parameter decorators exist but are rarely used.
Execution order is fixed: property decorators run first (top to bottom), then accessor, then method, then parameter, and finally class decorator. Within the same type, decorators run from bottom to top (i.e., the one closest to the method declaration runs first). This matters when you combine multiple decorators.
A decorator factory is a function that returns the actual decorator. It allows you to pass parameters: @log('info'). The factory runs once when the class is defined, and the returned decorator runs during decoration.
A team had a @authenticate and @validate on the same method. The validation decorator ran first, crashing because the user wasn't authenticated yet.
The fix was to reorder decorators: @authenticate @validate ensures authentication runs first.
Rule: Decorators execute bottom-up on the same element — the one closest to the method declaration runs first.
🎯 Key Takeaway
Decorator factories run top-down; decorator application runs bottom-up (for same element type).
Property decorators execute before method decorators, before class decorators.
Always document the intended order when combining multiple decorators on a single target.
Metadata Reflection with reflect-metadata
The reflect-metadata polyfill is the backbone of decorator metadata in TypeScript. When emitDecoratorMetadata is enabled, TypeScript automatically emits metadata about the decorated element, including: - design:type — the type of the property or parameter - design:paramtypes — the parameter types of a method - design:returntype — the return type of a method
This is how frameworks like Angular and NestJS resolve dependency injection at runtime. Without the polyfill, Reflect.getMetadata throws.
Key gotcha: The metadata is collected at class definition time, not instantiation time. If a decorated class is imported but never instantiated, the metadata is still generated and stored in the global Reflect map. This can cause memory leaks if not managed.
Also, reflect-metadata must be imported as a side effect — import 'reflect-metadata' — before any decorator is evaluated. If you import it lazily or inside a module, it may not be loaded in time.
Without import 'reflect-metadata', any call to Reflect.getMetadata returns undefined. Frameworks that rely on metadata (Angular, TypeORM) will fail silently — injection appears to work but properties remain null. Always import the polyfill at your application entry point before any class definition.
📊 Production Insight
A microservice stopped injecting dependencies after a Webpack upgrade. The reflect-metadata polyfill was no longer imported early enough because of module reordering.
The fix: add import 'reflect-metadata' at the top of the entry file, before any app code.
Rule: Treat reflect-metadata as a critical polyfill with strict ordering requirements — import it first, always.
🎯 Key Takeaway
reflect-metadata is a polyfill that must be imported as a side effect before any decorator evaluation.
TypeScript automatically emits design:* metadata when emitDecoratorMetadata is true.
Missing polyfill leads to silent injection failures — the most common decorator bug in production.
Enums as Bitflags: The Feature Everyone Misuses
Most devs treat TypeScript enums like numbered menus. But numeric enums with bitwise operators give you something far more powerful: compile-time checked flag combinations. Instead of passing three separate booleans to a function, pass a single enum bitmask. The real win? TypeScript validates every combination at compile time. Reverse lookups still work. The JS output is just integers. No runtime overhead. Just cleaner APIs. The catch? Bitwise enums require explicit values in powers of 2. Default auto-incrementing enums won't work. You must define them manually. Your team will either love this or file a PR to remove it. Use sparingly. Only when the abstraction pays off in readability. Otherwise, you're just showing off.
Never use const enum with bitflags. The reverse mapping breaks. Always use regular enums for mask patterns.
🎯 Key Takeaway
Bitflag enums replace boolean overloads. But only for stable, well-understood permission sets.
Decorators on Enum Members: Why They Fail Silently
You can slap a decorator on an enum member. TypeScript won't complain. But it won't work in production. Decorators on enum members are erased at runtime. The decorator function never executes. This isn't a bug — it's intentional. The TC39 spec never included enum member decorators because enums are just objects when compiled. The decorator gets assigned to a property that doesn't exist yet. Your code compiles. Your tests pass (because they run in the same process). But your production bundle silently drops the decorator. I've seen teams chase this for days. The fix? Don't decorate enum members. Use a separate map with the decorator applied to the container object. Or refactor to a class with static members.
Use a Map<Status, Metadata> with decorators applied to the map's getter. Keeps metadata attached without runtime surprises.
🎯 Key Takeaway
Decorators on enum members compile fine but vanish in production. Use a separate metadata map instead.
thecodeforge.io
Typescript Enums Decorators
Reverse Mapping with reflect-metadata: When Numbers Lie
Every numeric enum generates a reverse mapping automatically. Status[0] returns 'Pending'. But throw in decorators with reflect-metadata, and the reverse map becomes unreliable. Why? Because reflect-metadata stores data on the constructor's prototype. Enums have no prototype. They're plain functions. So Reflect.getMetadata on an enum member returns undefined. Never fails. Just returns nothing. The fix: store metadata on a closure object inside the decorator factory. Or use Reflect.defineMetadata on the enum function itself. Either way, you must account for the inheritance gap. This killed half a day of debugging for a payments team I consulted for. Don't assume metadata works on enums. Test it.
metadata-trap.tsTYPESCRIPT
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
import'reflect-metadata';
functionMeta(value: string) {
returnReflect.metadata('key', value);
}
enumColor {
@Meta('red')
Red = 0,
@Meta('blue')
Blue = 1
}
console.log(Reflect.getMetadata('key', Color, 'Red'));
// undefined — decorator executed on non-existent prototype
console.log(Reflect.getMetadata('key', Color, 0));
// undefined — this works on classes, not enums
Never assume reflect-metadata works on enums. Always wrap your enum in a class if you need metadata-driven serialization.
🎯 Key Takeaway
Enums have no prototype chain. reflect-metadata returns undefined silently. Test metadata access at compile time.
● Production incidentPOST-MORTEMseverity: high
Enum Reverse Mapping Blew Up a Shared Library Bundle
Symptom
A shared TypeScript library grew to 12KB when it should have been 2KB. The entire enum object — including reverse mapping — was included in every consumer bundle, even if only one enum value was used.
Assumption
The library author assumed tree-shaking would remove unused enum values. They used a regular enum because it was simpler to debug in development.
Root cause
TypeScript's regular enum emits a var Status; (function (Status) { Status[Status["Active"] = 0] = "Active"; ... })(Status || (Status = {})); — the reverse mapping object is always generated and cannot be tree-shaken because the function invocation is a side effect.
Fix
Switch to const enum for library exports when the enum is used as a set of named constants. Const enums completely inline at compile time — no runtime overhead. For internal libraries, use plain union types or string literal types if possible.
Key lesson
Prefer const enum in library code to avoid bundle bloat.
For public APIs, consider using a plain object with as const to avoid reverse mapping altogether.
Production debug guideSymptom→Action guide for the most common failures3 entries
Symptom · 01
Enum value is undefined at runtime even though the code compiles
→
Fix
Check if the enum is a const enum and the consumer module has isolatedModules or verbatimModuleSyntax enabled. Const enums are not inlined across module boundaries without preserveConstEnums.
Symptom · 02
Decorator function never executes; no effect on class or method
→
Fix
Verify that experimentalDecorators and emitDecoratorMetadata are enabled in tsconfig.json. Also confirm that reflect-metadata is imported as a side effect at the entry point (e.g., import 'reflect-metadata').
Symptom · 03
Reflect.getMetadata returns undefined for a decorated class
→
Fix
Check decorator factory signature — a factory must return the actual decorator function. Also confirm metadata keys match exactly (strings are case-sensitive). Use Reflect.defineMetadata explicitly if the decorator is hand-written.
★ Enum & Decorator Quick Debug Cheat SheetCommon symptoms and the exact commands to diagnose them in production or CI
Bundle includes reverse mapping when it shouldn't−
Enable experimentalDecorators: true in tsconfig. If using Angular or NestJS, ensure the reflect-metadata polyfill is imported before any class definition.
Enum value is correct in test but wrong in production build+
Immediate action
Check if the production build uses a bundler that transforms enums. Webpack's `mode: production` can override enum values via DefinePlugin.
Avoid relying on numeric enum values in production — use string enums or as const objects for values that must be stable across builds.
TypeScript Enums & Decorators Concept Comparison
Concept
Use Case
Example
Regular enum
Runtime iteration, reverse mapping
enum Color { Red, Green }
Const enum
Zero bundle overhead, internal constants
const enum Color { Red, Green }
String enum
Meaningful values, no reverse mapping
enum Status { OK = 'OK' }
Decorator factory
Parameterized decorators
@log('info')
Metadata decorator
Dependency injection, validation
@Injectable() with emitDecoratorMetadata
⚙ Quick Reference
6 commands from this guide
File
Command / Code
Purpose
enums-compile-examples.ts
enum HttpStatus { OK = 200, NotFound = 404 }
How TypeScript Enums Compile to JavaScript
decorator-order.ts
function first() {
Decorator Syntax and Execution Order
reflect-metadata-example.ts
function Injectable() {
Metadata Reflection with reflect-metadata
permissions.ts
enum Permission {
Enums as Bitflags
broken-decorator.ts
function Log(target: any, key: string) {
Decorators on Enum Members
metadata-trap.ts
function Meta(value: string) {
Reverse Mapping with reflect-metadata
Key takeaways
1
Regular enum compiles to an IIFE with reverse mapping
adds bundle weight that tree-shaking can't remove.
2
Const enum inlines everything but breaks with isolatedModules
use for internal code, not libraries.
3
Decorator factories run top-down; decorators apply bottom-up
order is crucial for composability.
4
reflect-metadata is a mandatory polyfill for decorator metadata
import it as a side effect before any decorated class is defined.
5
Prefer as const + union types over enums for public APIs
same safety, zero runtime cost, full tree-shaking.
Common mistakes to avoid
4 patterns
×
Memorising syntax before understanding the concept
Symptom
Developers can recite decorator factory syntax but cannot explain when or why to use one. Code reviews show decorators applied to methods that don't need them, or enums used where a union type would be simpler.
Fix
Focus on the problem first: Do I need to restrict values? Use an enum or union. Do I need to add cross-cutting behaviour without modifying the method? Use a decorator. The syntax will come with practice.
×
Skipping practice and only reading theory
Symptom
Senior engineers read this article but never open an editor. They later struggle to debug a const enum issue because they've never seen the compiled output.
Fix
Open a TypeScript playground after each section. Emit JavaScript with tsc --target ES2015 and inspect the output. Write a custom decorator and verify metadata is emitted.
×
Using regular enums in an npm library without considering bundle size
Symptom
Library consumers report unexpected bundle size increase. The enum IIFE cannot be tree-shaken away.
Fix
Use const enum and export the .d.ts. Alternatively, use a plain as const object with a type helper: const Status = { Active: 0, Inactive: 1 } as const; type Status = (typeof Status)[keyof typeof Status];
×
Forgetting to import reflect-metadata when using decorator metadata
Symptom
Decorated classes compile fine but at runtime Reflect.getMetadata returns undefined. Dependency injection fails silently.
Fix
Add import 'reflect-metadata' at the entry point before any decorator is evaluated. Ensure the import is not tree-shaken away by a bundler.
INTERVIEW PREP · PRACTICE MODE
Interview Questions on This Topic
Q01SENIOR
What is the difference between a regular enum and a const enum in TypeSc...
Q02SENIOR
Explain the execution order of multiple decorators on a single method. H...
Q03SENIOR
What does `emitDecoratorMetadata` do, and what is the reflect-metadata p...
Q04SENIOR
How can you avoid the bundle size cost of enums in a public npm library?
Q01 of 04SENIOR
What is the difference between a regular enum and a const enum in TypeScript? When would you use each?
ANSWER
A regular enum compiles to a JavaScript object stored in an IIFE, which includes both forward and reverse mappings. It is available at runtime and can be iterated. A const enum is completely inlined — it disappears at compile time and the values are inserted as literals. Use regular enums when you need runtime iteration or reverse mapping, and when the enum is not in a library. Use const enums for internal app constants where you want zero runtime overhead and you control the build pipeline. For libraries, prefer const enum with preserveConstEnums or avoid enums entirely and use as const objects.
Q02 of 04SENIOR
Explain the execution order of multiple decorators on a single method. How does it affect production behaviour?
ANSWER
For multiple decorators on a method, the decorator closest to the method runs first. For example, @first @second method() runs second before first (bottom-up). The factory functions that produce the decorators run top-down. This ordering matters when decorators have dependencies — e.g., a logging decorator should run outside an authentication decorator. In production, a common bug is putting validation before authentication; the validator runs first, crashes because the user isn't authenticated yet.
Q03 of 04SENIOR
What does `emitDecoratorMetadata` do, and what is the reflect-metadata polyfill for?
ANSWER
emitDecoratorMetadata is a TypeScript compiler option that tells the compiler to emit metadata about the types of decorated members. It generates design:type, design:paramtypes, and design:returntype keys that can be accessed via Reflect.getMetadata. The reflect-metadata polyfill provides the Reflect.metadata API for environments that don't have it natively (e.g., Node.js before version 19). Without the polyfill, Reflect.getMetadata throws an error. The polyfill must be imported as a side effect at the entry point before any decorator is evaluated.
Q04 of 04SENIOR
How can you avoid the bundle size cost of enums in a public npm library?
ANSWER
Use const enum and ensure your library's tsconfig has preserveConstEnums: true so the runtime object is still emitted for consumers that cannot use const enums due to isolatedModules. Even better, avoid enums entirely and use a constant object with as const and a union type derived from it. That gives zero runtime overhead, no IIFE, full tree-shakability, and no reverse mapping surprise. Example: export const Status = { Active: 0, Inactive: 1 } as const; export type Status = (typeof Status)[keyof typeof Status];
01
What is the difference between a regular enum and a const enum in TypeScript? When would you use each?
SENIOR
02
Explain the execution order of multiple decorators on a single method. How does it affect production behaviour?
SENIOR
03
What does `emitDecoratorMetadata` do, and what is the reflect-metadata polyfill for?
SENIOR
04
How can you avoid the bundle size cost of enums in a public npm library?
SENIOR
FAQ · 4 QUESTIONS
Frequently Asked Questions
01
Can I use const enums in a TypeScript project with isolatedModules enabled?
Yes, but only if the const enum is defined in the same file. As soon as you export a const enum from a separate file and import it, TypeScript will warn with TS2748: Cannot access ambient const enums when 'isolatedModules' is enabled. To work around, either disable isolatedModules (not recommended for modern projects) or add preserveConstEnums: true to your tsconfig — which will emit a regular enum alongside the const enum, negating the bundle benefit.
Was this helpful?
02
Why is my decorator not running at all?
Check that experimentalDecorators is enabled in tsconfig. Also ensure your decorator is applied correctly (e.g., @decorator without parentheses if it's a simple decorator, or @decorator() if it's a factory). If using class decorators and the class is never instantiated, the decorator will still run at class definition time. If you're using metadata, verify reflect-metadata is imported before any decorator evaluation.
Was this helpful?
03
What's the difference between a method decorator and a property decorator?
A method decorator receives three arguments: the target (prototype for instance methods, constructor for static), the property key, and the property descriptor. It can modify the descriptor to wrap or replace the method. A property decorator receives only the target and property key — no descriptor, because property descriptors don't exist in the prototype chain. Property decorators are useful for adding metadata or rewriting the initialiser logic via Object.defineProperty.
Was this helpful?
04
Can enum values be computed at runtime?
Yes, regular and string enums can have computed values, but const enums cannot. For computed expressions, the enum member must have a value that can be evaluated at compile time if it's a const enum. For regular enums, you can use any expression: enum Size { Small = 1 << 0, Medium = 1 << 1 }. However, computed values prevent some optimizations and can make the resulting JavaScript harder to debug.