0
# Decorator Support
1
2
Handles decorator downleveling and output transformation for Closure Compiler property renaming compatibility, ensuring decorators work correctly with advanced optimization.
3
4
## Capabilities
5
6
### Decorator Downlevel Transformer
7
8
Main transformer for converting TypeScript decorators to ES5-compatible function calls.
9
10
```typescript { .api }
11
/**
12
* Main transformer factory for downleveling decorators
13
*/
14
function decoratorDownlevelTransformer(
15
typeChecker: ts.TypeChecker,
16
diagnostics: ts.Diagnostic[]
17
): ts.TransformerFactory<ts.SourceFile>;
18
```
19
20
**Usage Example:**
21
22
```typescript
23
import { decoratorDownlevelTransformer } from "tsickle";
24
25
const transformer = decoratorDownlevelTransformer(typeChecker, diagnostics);
26
27
// The transformer converts:
28
// @Component({ selector: 'app' })
29
// class AppComponent {}
30
//
31
// To:
32
// let AppComponent = class AppComponent {};
33
// AppComponent = __decorate([Component({ selector: 'app' })], AppComponent);
34
```
35
36
### Decorator Decision Logic
37
38
Function to determine whether a decorator should be downleveled based on its type and usage.
39
40
```typescript { .api }
41
/**
42
* Determines if decorator should be downleveled
43
*/
44
function shouldLower(decorator: ts.Decorator, typeChecker: ts.TypeChecker): boolean;
45
```
46
47
**Usage Example:**
48
49
```typescript
50
import { shouldLower } from "tsickle";
51
52
// Check if a decorator needs downleveling
53
const needsDownleveling = shouldLower(decoratorNode, typeChecker);
54
55
if (needsDownleveling) {
56
// Apply downleveling transformation
57
console.log("Decorator will be downleveled for Closure compatibility");
58
}
59
```
60
61
### Exporting Decorator Detection
62
63
Functions for identifying decorators that should preserve export information.
64
65
```typescript { .api }
66
/**
67
* Checks if node has an exporting decorator
68
*/
69
function hasExportingDecorator(node: ts.Node, typeChecker: ts.TypeChecker): boolean;
70
71
/**
72
* Returns declarations for a decorator
73
*/
74
function getDecoratorDeclarations(
75
decorator: ts.Decorator,
76
typeChecker: ts.TypeChecker
77
): ts.Declaration[];
78
```
79
80
**Usage Example:**
81
82
```typescript
83
import { hasExportingDecorator, getDecoratorDeclarations } from "tsickle";
84
85
// Check if a class has exporting decorators
86
if (hasExportingDecorator(classNode, typeChecker)) {
87
// This class will be marked for export preservation
88
const declarations = getDecoratorDeclarations(decoratorNode, typeChecker);
89
console.log(`Found ${declarations.length} decorator declarations`);
90
}
91
```
92
93
## Closure Property Renaming Support
94
95
### Property Renaming Transformer
96
97
Transformer that handles decorator output for Closure Compiler property renaming.
98
99
```typescript { .api }
100
/**
101
* Transforms decorator output for Closure property renaming
102
*/
103
function transformDecoratorsOutputForClosurePropertyRenaming(
104
diagnostics: ts.Diagnostic[]
105
): ts.TransformerFactory<ts.SourceFile>;
106
```
107
108
This transformer ensures that decorator metadata is preserved through Closure Compiler's property renaming process.
109
110
### JSDoc Decorator Transformer
111
112
Transformer for processing decorator-related JSDoc comments.
113
114
```typescript { .api }
115
/**
116
* Transforms decorator JSDoc
117
*/
118
function transformDecoratorJsdoc(): ts.TransformerFactory<ts.SourceFile>;
119
```
120
121
## Decorator Transformation Examples
122
123
### Class Decorators
124
125
```typescript
126
// Before transformation (TypeScript)
127
@Component({
128
selector: 'app-root',
129
templateUrl: './app.component.html'
130
})
131
export class AppComponent {
132
title = 'My App';
133
}
134
135
// After transformation (downleveled)
136
/** @nocollapse */
137
let AppComponent = class AppComponent {
138
constructor() {
139
this.title = 'My App';
140
}
141
};
142
AppComponent = __decorate([
143
Component({
144
selector: 'app-root',
145
templateUrl: './app.component.html'
146
})
147
], AppComponent);
148
exports.AppComponent = AppComponent;
149
```
150
151
### Method Decorators
152
153
```typescript
154
// Before transformation
155
class Service {
156
@cache()
157
getData(): Promise<Data> {
158
return fetch('/api/data');
159
}
160
}
161
162
// After transformation
163
class Service {
164
getData() {
165
return fetch('/api/data');
166
}
167
}
168
__decorate([
169
cache(),
170
__metadata("design:type", Function),
171
__metadata("design:paramtypes", []),
172
__metadata("design:returntype", Promise)
173
], Service.prototype, "getData", null);
174
```
175
176
### Property Decorators
177
178
```typescript
179
// Before transformation
180
class Model {
181
@observable
182
public value: string = '';
183
}
184
185
// After transformation
186
class Model {
187
constructor() {
188
this.value = '';
189
}
190
}
191
__decorate([
192
observable,
193
__metadata("design:type", String)
194
], Model.prototype, "value", void 0);
195
```
196
197
## Exporting Decorators
198
199
### @ExportDecoratedItems Pattern
200
201
Tsickle supports a special JSDoc annotation for decorators that should preserve their decorated items through Closure optimization:
202
203
```typescript
204
/**
205
* @ExportDecoratedItems
206
*/
207
function preserveExports(target: any) {
208
// Decorator implementation
209
}
210
211
@preserveExports
212
class ImportantClass {
213
// This class name will be preserved through optimization
214
}
215
```
216
217
The `@ExportDecoratedItems` annotation in the decorator's JSDoc tells tsickle to:
218
1. Add `@export` tags to decorated items
219
2. Preserve the original names through Closure compilation
220
3. Ensure the decorated items remain accessible after optimization
221
222
### Export Preservation
223
224
When a decorator is marked with `@ExportDecoratedItems`, tsickle automatically:
225
226
```typescript
227
// Original code
228
@preserveExports
229
class MyClass {}
230
231
// Generated output includes
232
/** @export */
233
class MyClass {}
234
```
235
236
## Integration with Other Systems
237
238
### Type System Integration
239
240
Decorator support integrates with the type translation system to:
241
- Preserve type information in decorator metadata
242
- Generate proper JSDoc for decorated members
243
- Handle generic decorators with type parameters
244
245
### Module System Integration
246
247
Decorator transformations work with the module system to:
248
- Properly import decorator functions in goog.module format
249
- Handle decorator dependencies across modules
250
- Ensure decorator metadata is available at runtime
251
252
### JSDoc Integration
253
254
Decorator processing coordinates with JSDoc generation to:
255
- Preserve existing JSDoc on decorated members
256
- Add required JSDoc annotations for Closure compatibility
257
- Handle decorator-specific JSDoc tags
258
259
## Configuration
260
261
Decorator behavior is controlled through the TsickleHost interface:
262
263
```typescript
264
interface TsickleHost {
265
/** Whether to downlevel decorators */
266
transformDecorators?: boolean;
267
// ... other options
268
}
269
270
// Usage
271
const host: TsickleHost = {
272
transformDecorators: true, // Enable decorator downleveling
273
transformTypesToClosure: true,
274
googmodule: true,
275
generateExtraSuppressions: true
276
};
277
```
278
279
## Runtime Requirements
280
281
For downleveled decorators to work correctly, the runtime environment must provide:
282
283
1. **__decorate function**: The decorator helper function
284
2. **__metadata function**: For design-time type metadata (when using reflect-metadata)
285
3. **Reflect.metadata**: If using reflection-based decorators
286
287
These are typically provided by:
288
- `tslib` for __decorate and __metadata
289
- `reflect-metadata` polyfill for Reflect.metadata
290
291
## Performance Considerations
292
293
Decorator processing is optimized for:
294
- **Selective downleveling**: Only downlevels decorators that need it
295
- **Metadata optimization**: Minimal metadata generation for better performance
296
- **Dead code elimination**: Unused decorators can be removed by Closure Compiler
297
- **Incremental compilation**: Only re-processes files with decorator changes