CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/npm-tsickle

Transpile TypeScript code to JavaScript with Closure annotations.

Pending
Overview
Eval results
Files

decorator-support.mddocs/

Decorator Support

Handles decorator downleveling and output transformation for Closure Compiler property renaming compatibility, ensuring decorators work correctly with advanced optimization.

Capabilities

Decorator Downlevel Transformer

Main transformer for converting TypeScript decorators to ES5-compatible function calls.

/**
 * Main transformer factory for downleveling decorators
 */
function decoratorDownlevelTransformer(
  typeChecker: ts.TypeChecker,
  diagnostics: ts.Diagnostic[]
): ts.TransformerFactory<ts.SourceFile>;

Usage Example:

import { decoratorDownlevelTransformer } from "tsickle";

const transformer = decoratorDownlevelTransformer(typeChecker, diagnostics);

// The transformer converts:
// @Component({ selector: 'app' })
// class AppComponent {}
//
// To:
// let AppComponent = class AppComponent {};
// AppComponent = __decorate([Component({ selector: 'app' })], AppComponent);

Decorator Decision Logic

Function to determine whether a decorator should be downleveled based on its type and usage.

/**
 * Determines if decorator should be downleveled
 */
function shouldLower(decorator: ts.Decorator, typeChecker: ts.TypeChecker): boolean;

Usage Example:

import { shouldLower } from "tsickle";

// Check if a decorator needs downleveling
const needsDownleveling = shouldLower(decoratorNode, typeChecker);

if (needsDownleveling) {
  // Apply downleveling transformation
  console.log("Decorator will be downleveled for Closure compatibility");
}

Exporting Decorator Detection

Functions for identifying decorators that should preserve export information.

/**
 * Checks if node has an exporting decorator
 */
function hasExportingDecorator(node: ts.Node, typeChecker: ts.TypeChecker): boolean;

/**
 * Returns declarations for a decorator
 */
function getDecoratorDeclarations(
  decorator: ts.Decorator,
  typeChecker: ts.TypeChecker
): ts.Declaration[];

Usage Example:

import { hasExportingDecorator, getDecoratorDeclarations } from "tsickle";

// Check if a class has exporting decorators
if (hasExportingDecorator(classNode, typeChecker)) {
  // This class will be marked for export preservation
  const declarations = getDecoratorDeclarations(decoratorNode, typeChecker);
  console.log(`Found ${declarations.length} decorator declarations`);
}

Closure Property Renaming Support

Property Renaming Transformer

Transformer that handles decorator output for Closure Compiler property renaming.

/**
 * Transforms decorator output for Closure property renaming
 */
function transformDecoratorsOutputForClosurePropertyRenaming(
  diagnostics: ts.Diagnostic[]
): ts.TransformerFactory<ts.SourceFile>;

This transformer ensures that decorator metadata is preserved through Closure Compiler's property renaming process.

JSDoc Decorator Transformer

Transformer for processing decorator-related JSDoc comments.

/**
 * Transforms decorator JSDoc
 */
function transformDecoratorJsdoc(): ts.TransformerFactory<ts.SourceFile>;

Decorator Transformation Examples

Class Decorators

// Before transformation (TypeScript)
@Component({
  selector: 'app-root',
  templateUrl: './app.component.html'
})
export class AppComponent {
  title = 'My App';
}

// After transformation (downleveled)
/** @nocollapse */
let AppComponent = class AppComponent {
  constructor() {
    this.title = 'My App';
  }
};
AppComponent = __decorate([
  Component({
    selector: 'app-root',
    templateUrl: './app.component.html'
  })
], AppComponent);
exports.AppComponent = AppComponent;

Method Decorators

// Before transformation
class Service {
  @cache()
  getData(): Promise<Data> {
    return fetch('/api/data');
  }
}

// After transformation
class Service {
  getData() {
    return fetch('/api/data');
  }
}
__decorate([
  cache(),
  __metadata("design:type", Function),
  __metadata("design:paramtypes", []),
  __metadata("design:returntype", Promise)
], Service.prototype, "getData", null);

Property Decorators

// Before transformation
class Model {
  @observable
  public value: string = '';
}

// After transformation
class Model {
  constructor() {
    this.value = '';
  }
}
__decorate([
  observable,
  __metadata("design:type", String)
], Model.prototype, "value", void 0);

Exporting Decorators

@ExportDecoratedItems Pattern

Tsickle supports a special JSDoc annotation for decorators that should preserve their decorated items through Closure optimization:

/**
 * @ExportDecoratedItems
 */
function preserveExports(target: any) {
  // Decorator implementation
}

@preserveExports
class ImportantClass {
  // This class name will be preserved through optimization
}

The @ExportDecoratedItems annotation in the decorator's JSDoc tells tsickle to:

  1. Add @export tags to decorated items
  2. Preserve the original names through Closure compilation
  3. Ensure the decorated items remain accessible after optimization

Export Preservation

When a decorator is marked with @ExportDecoratedItems, tsickle automatically:

// Original code
@preserveExports
class MyClass {}

// Generated output includes
/** @export */
class MyClass {}

Integration with Other Systems

Type System Integration

Decorator support integrates with the type translation system to:

  • Preserve type information in decorator metadata
  • Generate proper JSDoc for decorated members
  • Handle generic decorators with type parameters

Module System Integration

Decorator transformations work with the module system to:

  • Properly import decorator functions in goog.module format
  • Handle decorator dependencies across modules
  • Ensure decorator metadata is available at runtime

JSDoc Integration

Decorator processing coordinates with JSDoc generation to:

  • Preserve existing JSDoc on decorated members
  • Add required JSDoc annotations for Closure compatibility
  • Handle decorator-specific JSDoc tags

Configuration

Decorator behavior is controlled through the TsickleHost interface:

interface TsickleHost {
  /** Whether to downlevel decorators */
  transformDecorators?: boolean;
  // ... other options
}

// Usage
const host: TsickleHost = {
  transformDecorators: true, // Enable decorator downleveling
  transformTypesToClosure: true,
  googmodule: true,
  generateExtraSuppressions: true
};

Runtime Requirements

For downleveled decorators to work correctly, the runtime environment must provide:

  1. __decorate function: The decorator helper function
  2. __metadata function: For design-time type metadata (when using reflect-metadata)
  3. Reflect.metadata: If using reflection-based decorators

These are typically provided by:

  • tslib for __decorate and __metadata
  • reflect-metadata polyfill for Reflect.metadata

Performance Considerations

Decorator processing is optimized for:

  • Selective downleveling: Only downlevels decorators that need it
  • Metadata optimization: Minimal metadata generation for better performance
  • Dead code elimination: Unused decorators can be removed by Closure Compiler
  • Incremental compilation: Only re-processes files with decorator changes

Install with Tessl CLI

npx tessl i tessl/npm-tsickle

docs

core-transformation.md

decorator-support.md

externs-generation.md

index.md

jsdoc-processing.md

module-system.md

path-utilities.md

transformer-utilities.md

type-translation.md

tile.json