Git Product home page Git Product logo

reflection's Introduction

Version Status Build Status npm bundle size (minified + gzip) Coverage Status

Reflection

Lightweight ES Module implementation of reflect-metadata to work with TypeScript's experimental decorator support.

Why?

The main reason for this library is to provide a much smaller implementation that can be included as a module.

  • ES module
    • reflection can be loaded with <script type="module" src="..."></script>
  • Size (uncompressed)

Read about how to drop 20K from your production Angular app by switching to this.

Install

npm install @abraham/reflection

Usage

import '@abraham/reflection';
Reflect.defineMetadata(metadataKey, metadataValue, target);

You can also import Reflection:

import { Reflection as Reflect } from '@abraham/reflection';
Reflect.defineMetadata(metadataKey, metadataValue, target);

API

Reflection does not currently cover the complete API surface of reflect-metadata. The following methods are available:

Reflect.decorate(...);
Reflect.defineMetadata(...);
Reflect.getMetadata(...);
Reflect.hasMetadata(...);
Reflect.getOwnMetadata(...);
Reflect.hasOwnMetadata(...);
Reflect.metadata(...);

reflection's People

Contributors

abraham avatar alexanderwende avatar cbbfcd avatar dependabot[bot] avatar dulowski-marek avatar forehalo avatar jiby-aurum avatar just-boris avatar renovate-bot avatar sublimator avatar tripodsgames avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar

reflection's Issues

error TS2339: Property 'getMetadata' does not exist on type 'typeof Reflect'

Thanks for your reflection lib. I have tried it in my playground project as drop-in replacement for reflect-metadata, but I get the error:

error TS2339: Property 'getMetadata' does not exist on type 'typeof Reflect'

Project: https://github.com/ova2/frontend-tooling-tutorial/tree/master/typescript-playground/dependency-injection-container

Steps to reproduce:

  1. Clone the project https://github.com/ova2/frontend-tooling-tutorial
  2. Go to typescript-playground/dependency-injection-container
  3. Remove reflect-metadata from package.json and run "npm install"
  4. npm install @abraham/reflection
  5. Replace import 'reflect-metadata' by import '@abraham/reflection' in di-container.ts
  6. Run "npm run test" -> error

You will also see the error in your IDE because the proper getMetadata() is not found. Furthermore, I think the return value of this method in your TS definition file should be "any". This is the type in reflect-metadata.

Cannot use with Electron

I got an error saying:
Error [ERR_REQUIRE_ESM]: require() of ES Module D:\ws\terminal\node_modules\@abraham\reflection\dist\index.umd.js from D:\ws\terminal\packages\main\dist\index.cjs not supported. index.umd.js is treated as an ES module file as it is a .js file whose nearest parent package.json contains "type": "module" which declares all .js files in that package scope as ES modules. Instead rename index.umd.js to end in .cjs, change the requiring code to use dynamic import() which is available in all CommonJS modules, or change "type": "module" to "type": "commonjs" in D:\ws\terminal\node_modules\@abraham\reflection\package.json to treat all .js files as CommonJS (using .mjs for all ES modules instead).
Because Electron doesn't support ES Modules for now, I have to manually change the index.umd.js to index.cjs to make it work. Is there any solutions?

can not work with vite

Run code in project created by vite

import '@abraham/reflection';

const classDecorator = (target: Object) => {
  console.log(Reflect.getMetadata('design:paramtypes', target));
};

const propertyDecorator = (target: Object, key: string | symbol) => {
  console.log(Reflect.getMetadata('design:type', target, key));
  console.log(Reflect.getMetadata('design:paramtypes', target, key));
  console.log(Reflect.getMetadata('design:returntype', target, key));
};

// paramtypes -> [String] 即构造函数接收的参数
@classDecorator
class Demo {
  innerValue: string;

  constructor(val: string) {
    this.innerValue = val;
  }

  /*
   * 元数据的值如下:
   * type -> String
   * paramtypes -> undefined
   * returntype -> undefined
   */
  @propertyDecorator
  demo1: string = 'demo1';

  /*
   * 元数据的值如下:
   * type -> Function
   * paramtypes -> [String]
   * returntype -> String
   */
  @propertyDecorator
  demo2(str: string): string {
    return str;
  }
}

Setup tests with several frameworks

Add an examples directory with a simple app of each of the following frameworks/libraries. The samples should make use of Reflection and have their tests run on CI. This will provide examples for developers of those libraries and make sure Reflection doesn't break compatibility. Lerna might be a good choice to manage the examples.

Doesn't work with InversifyJS

Minimal reproducible example:

import "@abraham/reflection";
import { Container, injectable } from "inversify";

const myContainer = new Container();

const TYPES = {
  Ninja: Symbol("Ninja")
};

@injectable()
class Ninja {}

myContainer.bind<Ninja>(TYPES.Ninja).to(Ninja);

const ninja = myContainer.get<Ninja>(TYPES.Ninja);

Throws error:

Uncaught TypeError: Reflect.hasMetadata is not a function
    at _postConstruct (instantiation.js:24)
    at Object.resolveInstance (instantiation.js:47)
    at resolver.js:72
    at Object.resolve (resolver.js:96)
    at container.js:319
    at Container../node_modules/inversify/lib/container/container.js.Container._get (container.js:310)
    at Container../node_modules/inversify/lib/container/container.js.Container.get (container.js:230)
    at Object../src/inversifytest.ts (inversifytest.ts:15)
    at __webpack_require__ (bootstrap ee47681dc696ba0b4a90:678)
    at fn (bootstrap ee47681dc696ba0b4a90:88)
    at Object../src/index.tsx (index.tsx:1)
    at __webpack_require__ (bootstrap ee47681dc696ba0b4a90:678)
    at fn (bootstrap ee47681dc696ba0b4a90:88)
    at Object.0 (inversifytest.ts:15)
    at __webpack_require__ (bootstrap ee47681dc696ba0b4a90:678)
    at bootstrap ee47681dc696ba0b4a90:724
    at bootstrap ee47681dc696ba0b4a90:724

I tested it within webpack but error is pretty clear. @abraham/reflection doesn't define Reflect.hasMetadata.

Decorator is not applicable to a method

The following code

import { Reflection } from '@abraham/reflection';

const decorator = Reflection.metadata('key', 'value');

export default class Test {

    @decorator
    method() {
        // empty
    }
}

Fails with the error

src/index.ts:88:28 - error TS2345: Argument of type 'Target' is not assignable to parameter of type 'Function'.
  Type '{}' is missing the following properties from type 'Function': apply, call, bind, prototype, and 5 more.

88     descriptor = decorator(target, propertyKey, descriptor) || descriptor;
                              ~~~~~~

The issue is at this line https://github.com/abraham/reflection/blob/master/src/index.ts#L54 It should use broader Target type instead of Function.

This package is somehow disturbing monaco editor? - Uncaught TypeError: Cannot read property 'value' of undefined at decorators.ts

This is just a hypothesis. I'm here to ask the author if this is a valid theory.
suren-atoyan/monaco-react#237

  1. The monaco react is using monaco internally.
  2. the project designto-code is using monaco react and flutter-builder.
  3. flutter-builder uses abraham/reflection for custom decorator. the issue is caused from decorators.ts:12

I'm not sure if monaco is crashing reflection or reflection is crashing monaco

image

As an expert, author of this library, please share your thoughts!

Uncaught TypeError: can't access property "hasOwnProperty", descriptor is undefined

Using decorators on static methods cause this error.

Uncaught TypeError: can't access property "hasOwnProperty", descriptor is undefined

image

CODE

function DecoratorTest(): MethodDecorator {
  return (target: object, method: string | symbol, descriptor: PropertyDescriptor): PropertyDescriptor => {
    console.log(`target: ${target}`);
    console.log(`method: ${method?.toString()}`);
    console.log(`descriptor: ${descriptor}`);
    console.log(target, method, descriptor);
    
    if (descriptor.hasOwnProperty('get') && descriptor.get) {
      return descriptor;
    }

    if (!descriptor.hasOwnProperty('set') && descriptor.value) {
      return descriptor;
    }

    throw new Error(`Invalid`);
  };
}

class Test {
  @DecoratorTest()
  test() {
  }

  @DecoratorTest()
  public static getCurrentIP() {
  }
}

new Test();

Import as ES Module doesn't work

Is there an example how to import it as ES module?

I am trying to import it like this:
https://codesandbox.io/s/musing-haze-v6my1

<body></body>
<script type="module">
  import * as Reflect from "https://unpkg.com/@abraham/reflection";
  document.body.innerHTML = `
    <div>
      Reflect:<br>
      typeof Reflect: ${typeof Reflect}<br>
      typeof Reflect.defineMetadata: ${typeof Reflect.defineMetadata}<br>
      JSON.stringify(Reflect): ${JSON.stringify(Reflect)}<br>
    </div>
  `;
</script>

output:

Reflect:
typeof Reflect: object
typeof Reflect.defineMetadata: undefined
JSON.stringify(Reflect): {}

build: ship commonjs version for node and testing

Currently if i wanna use same polyfills in testing environment ( jest ) like in dev/prod with typescript I have to do a lot of ceremony:

  • in jest config
{
transformIgnorePatterns: [
    '<rootDir>/node_modules/(?!@abraham/reflection/.*)',
  ],
}
  • in tsconfig
{
"allowJs": true
}

this is rather hack then good DX experience :)

shipping commonJS bundle is a no brainer and would help a lot ;) cheers

circular references are not working

According to my testing, circular references are not working, just like reflect-metadata (typescript seems to be the root cause).

It'd need a workaround to be supported... AFAIK, Angular uses forward refs

Breaking in Chrome 71

First of all, thanks for this library. I was just recently inspecting the code of reflect-metadata and was shocked about all the hard-coded shims it is shipping with. I thought to myself, I should maybe create a fork and strip out all the unnecessary code - and then I found your package. Just what I needed. :)

Today I tried using it in a project of mine which previously used reflect-metadata for decorators and the actual metadata API. When running the tests, I suddenly got TypeError: Reflect.construct is not a function.

After some digging I found that Reflect was replaced entirely with the Reflection export of the es6 module, instead of being extended with it. The culprit seems to be the following part in index.ts:

// TODO: Is this a good approach?
(window as any).Reflect = Object.assign({}, Reflect, Reflection);

There seems to be a problem with Object.assign({}, Reflect) which returns an empty object in Chrome. It actually seems to happen for all built in global objects - at least in Chrome 71.

If I simply replace this line with:

Object.assign(Reflect, Reflection);

Everything works fine. What do you think? I also think it could be safer doing it that way, because if any code imported before your module references Reflect, your module will replace the global reference and suddenly we have 2 Reflects hanging around.

Syntax error—IE11 support?

I quickly discovered that you use lamda functions. They blow up in IE11. I couldn't find any documentation staying what your intentions for this library were. Can you (at least) add a note to your readme about what browsers are supported? Thanks.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.