type-graphql icon indicating copy to clipboard operation
type-graphql copied to clipboard

Support `core-js/features/reflect`?

Open KeithGillette opened this issue 2 years ago • 6 comments

Is your feature request related to a problem? Please describe. Our project uses the Reflect polyfill provided in core-js since core-js provides a range of other useful polyfills. However, when we attempt to use type-graphql with core-js/features/reflect, we get the following error: ReflectMetadataMissingError: Looks like you've forgot to provide experimental metadata API polyfill. Please read the installation instruction for more details.

Describe the solution you'd like Update the type-graphql check for a Reflect polyfill to support the core-js implementation as well as reflect-metadata.

KeithGillette avatar Oct 31 '21 15:10 KeithGillette

As you can see, TypeGraphQL only checks with a duck-typing approach if the Reflect polyfill is provided: https://github.com/MichalLytek/type-graphql/blob/9555a94adcde7cecc9b0a04e335a4f6ca2469a21/src/metadata/utils.ts#L60-L68

So something must be wrong with your setup as TypeGraphQL does not require reflect-metadata directly.

MichalLytek avatar Oct 31 '21 15:10 MichalLytek

Thanks for the fast reply, @MichalLytek. It looks like the second test is triggering the failure with core-js, as if I add the following to our main.ts entry point:

import 'core-js/features/reflect/';
console.log(typeof Reflect !== 'object' ); // false
console.log(typeof Reflect.decorate !== 'function'); // true
console.log(typeof Reflect.metadata !== 'function'); // false

While reflect-metadata defines Reflect.decorate, neither core-js nor reflect-metadata list it in their API documentation. As far as I can surmise, Reflect.decorate is not part of the ECMAScript proposal but an internal implementation detail of the reflect-metadata polyfill.

KeithGillette avatar Oct 31 '21 18:10 KeithGillette

Correct me if I'm wrong, but that's what TypeScript compiler requires in order to properly transpile decorators:

var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
    var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
    if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
    else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
    return c > 3 && r && Object.defineProperty(target, key, r), r;
};

MichalLytek avatar Oct 31 '21 18:10 MichalLytek

I don’t know enough about TypeScript internals to say but it does seem to be the case. However, the code snippet you quote includes a fall-back if the test for Reflect.decorate fails, I’m assuming because most projects don’t import a Reflect polyfill at all since runtime reflection is not needed. Isn’t the question whether any of the type-graphql code calls Reflect.decorate? A quick repository search didn’t turn up any calls, leading me to believe the existence test for that particular method is superfluous for this library, but perhaps I’m missing something.

KeithGillette avatar Oct 31 '21 20:10 KeithGillette

TypeGraphQL itself indeed does not call Reflect.decorate. The runtime check is there because a lot of newcomers don't read the docs and forgot to install deps and configure TS properly 😛

I don't know, maybe we can remove the check for Reflect.decorate === "function", leaving only the metadata one... 🤔

MichalLytek avatar Oct 31 '21 20:10 MichalLytek

Yes, having a runtime check to produce a friendly error message makes sense. I think that removing the check for Reflect.decorate would allow using any polyfill that only implements the public Reflect API proposal.

KeithGillette avatar Oct 31 '21 20:10 KeithGillette