1. babel-plugin-transform-typescript-metadata
Babel plugin to emit decorator metadata like typescript compiler
babel-plugin-transform-typescript-metadata
Package: babel-plugin-transform-typescript-metadata
Created by: leonardfactory
Last modified: Mon, 11 Apr 2022 16:45:54 GMT
Version: 0.3.2
License: MIT
Downloads: 5,679,683
Repository: https://github.com/leonardfactory/babel-plugin-transform-typescript-metadata

Install

npm install babel-plugin-transform-typescript-metadata
yarn add babel-plugin-transform-typescript-metadata

babel-plugin-transform-typescript-metadata

Travis (.com)
Codecov
npm

Babel plugin to emit decorator metadata like typescript compiler

Motivation

TypeScript Decorators allows advanced reflection patterns when combined
with Reflect.metadata output.

Current @babel/preset-typescript implementation however just strips all types and
does not emit the relative Metadata in the output code.

Since this kind of information is used extensively in libraries like
Nest and TypeORM
to implement advanced features like Dependency Injection, I've thought it would
be awesome to be able to provide the same functionality that TypeScript
compiler experimentalDecorators and emitDecoratorMetadata
flags
provide.

This means that code like:

 import { Injectable, Inject } from 'some-di-library'; // Just an example
import { MyService } from './MyService';
import { Configuration } from './Configuration';

@Injectable()
class AnotherService {
  @Inject()
  config: Configuration;

  constructor(private service: MyService) {}
}

will be interpreted like:

 import { MyService } from './MyService';
import { Configuration } from './Configuration';

@Injectable()
@Reflect.metadata('design:paramtypes', [MyService])
class AnotherService {
  @Inject()
  @Reflect.metadata('design:type', Configuration)
  config: Configuration;

  constructor(private service: MyService) {}
}

Parameter decorators

Since decorators in typescript supports also Parameters, this plugin
also provides support for them, enabling the following syntax:

 @Injectable()
class Some {
  constructor(@Inject() private: SomeService);
}

This will be roughly translated to:

 // ...
Inject()(Some.prototype, undefined, 0);

Installation

With npm:

 npm install --dev --save babel-plugin-transform-typescript-metadata

or with Yarn:

 yarn add --dev babel-plugin-transform-typescript-metadata

Usage

With .babelrc:

Note: should be placed before @babel/plugin-proposal-decorators.

 {
  "plugins": [
    "babel-plugin-transform-typescript-metadata",
    ["@babel/plugin-proposal-decorators", { "legacy": true }],
    ["@babel/plugin-proposal-class-properties", { "loose": true }],
  ],
  "presets": [
    "@babel/preset-typescript"
  ]
}

Usage with InversifyJS

If you are using normal dependency injection letting Inversify create your instances, you should be fine with all kind of decorators.

Instead, if you are using property injection, when the container does not
create the instances
,
you would likely encounter errors since babel
decorators are not exactly the same as TypeScript.

You can fix it by enhancing property decorators with the following function:

 import getDecorators from 'inversify-inject-decorators';
// setup the container...
let { lazyInject: originalLazyInject } = getDecorators(container);

// Additional function to make properties decorators compatible with babel.
function fixPropertyDecorator<T extends Function>(decorator: T): T {
  return ((...args: any[]) => (
    target: any,
    propertyName: any,
    ...decoratorArgs: any[]
  ) => {
    decorator(...args)(target, propertyName, ...decoratorArgs);
    return Object.getOwnPropertyDescriptor(target, propertyName);
  }) as any;
}

export const lazyInject = fixPropertyDecorator(originalLazyInject);

Current Pitfalls

  • If you are using webpack and it complains about missing exports due to types
    not being removed, you can switch from import { MyType } from ... to
    import type { MyType } from .... See #46 for details and
    examples.

  • We cannot know if type annotations are just types (i.e. IMyInterface) or
    concrete values (like classes, etc.). In order to resolve this, we emit the
    following: typeof Type === 'undefined' ? Object : Type. The code has the
    advantage of not throwing. If you know a better way to do this, let me know!

RELATED POST

10 Must-Know Windows Shortcuts That Will Save You Time

10 Must-Know Windows Shortcuts That Will Save You Time

Arrays vs Linked Lists: Which is Better for Memory Management in Data Structures?

Arrays vs Linked Lists: Which is Better for Memory Management in Data Structures?

Navigating AWS Networking: Essential Hacks for Smooth Operation

Navigating AWS Networking: Essential Hacks for Smooth Operation

Achieving Stunning Visuals with Unity's Global Illumination

Achieving Stunning Visuals with Unity's Global Illumination

Nim's Hidden Gems: Lesser-known Features for Writing Efficient Code

Nim's Hidden Gems: Lesser-known Features for Writing Efficient Code