babel-plugin-transform-typescript-metadata
    TypeScript icon, indicating that this package has built-in type declarations

    0.3.2 • Public • Published

    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!

    Install

    npm i babel-plugin-transform-typescript-metadata

    DownloadsWeekly Downloads

    196,172

    Version

    0.3.2

    License

    MIT

    Unpacked Size

    30.2 kB

    Total Files

    16

    Last publish

    Collaborators

    • leonardfactory