Type-graphql: TypeError: Reflect.getMetadata is not a function

Created on 5 Feb 2018  路  7Comments  路  Source: MichalLytek/type-graphql

Hi there :wave:
I've posted this question on the apollo slack #general and after looking up and testing all projects related to this on github I finally stumble upon this amazing project. I am very hopeful on this one.

Our project have a lot of types definitions written in typescript as interfaces, so reusing them would be a great benefit in terms of time, reusability, type safety ,stability and greatness :)

So thank you for maintaining this 馃憤
Still, I am having a hard time trying to get a minimal viable example working.

"dependencies": {
  "reflect-metadata": "^0.1.12",
  "type-graphql": "^0.1.2"
}
// example.ts
import {Field, GraphQLObjectType, ID} from 'type-graphql';

@GraphQLObjectType()
class Recipe {
    @Field(type => ID)
    readonly id: string;

    @Field()
    title: string;

    @Field({nullable: true})
    description?: string;

    @Field({nullable: true})
    averageRating?: number;
}

// test.ts
import {buildSchema} from 'type-graphql';
import {Recipe} from './example';

function test() {
    const schema = buildSchema({
        resolvers: [Recipe],
    });
    console.log(schema);
}

test();
ts-node -O '{"module": "commonjs"}' test.ts
[..]\node_modules\type-graphql\helpers\findType.js:7
    const reflectedType = Reflect.getMetadata(metadataKey, prototype.constructor.prototype, propertyKey);
                                  ^
TypeError: Reflect.getMetadata is not a function
    at Object.findType ([..]\node_modules\type-graphql\helpers\findType.js:7:35)
    at Field ([..]\node_modules\type-graphql\decorators\Field.js:14:53)
    at __decorate ([..]\src\main\ts\models\example\example.js:5:110)
    at Object.<anonymous> ([..]\src\main\ts\models\example\example.ts:6:5)
    at Module._compile (module.js:660:30)
    at Object.Module._extensions..js (module.js:671:10)
    at Module.load (module.js:573:32)
    at tryModuleLoad (module.js:513:12)
    at Function.Module._load (module.js:505:3)
    at Module.require (module.js:604:17)

Any help would be much appreciated.

Question Solved

Most helpful comment

Hi @4F2E4A2E!
Thanks, I'm glad to hear that 馃槉

Reflect.getMetadata is not a function means you haven't imported the reflect-metadata shim. Please take a look at the installation section:
https://github.com/19majkel94/type-graphql#installation

reflect-metadata shim is required:
make sure to import it on top of your entry file (before you use/import type-graphql or your resolvers):

You can see this in the examples on the repo too:
https://github.com/19majkel94/type-graphql/blob/master/examples/01-simple-usage/index.ts#L1

All 7 comments

Hi @4F2E4A2E!
Thanks, I'm glad to hear that 馃槉

Reflect.getMetadata is not a function means you haven't imported the reflect-metadata shim. Please take a look at the installation section:
https://github.com/19majkel94/type-graphql#installation

reflect-metadata shim is required:
make sure to import it on top of your entry file (before you use/import type-graphql or your resolvers):

You can see this in the examples on the repo too:
https://github.com/19majkel94/type-graphql/blob/master/examples/01-simple-usage/index.ts#L1

doh! Of course i forgot about the reflect-metadata import, sorry for that. The minimal example worked just fine.
Is there also a way of converting interfaces directly? Like so:

@GraphQLObjectType()
export interface Recipe {
    @Field(type => ID)
    readonly id: string;

    @Field()
    title: string;

    @Field({nullable: true})
    description?: string;

    @Field({nullable: true})
    averageRating?: number;
}

No, interfaces are removed at compilation so they doesn't exist at runtime. However you can just use abstract classes as interfaces 馃槈

@GraphQLObjectType()
export abstract class IRecipe {
    @Field(type => ID)
    readonly id: string;

    @Field()
    title: string;

    @Field({nullable: true})
    description?: string;

    @Field({nullable: true})
    averageRating?: number;
}

class SpecialRecipe implements IRecipe {
  // impl...
}

It's working fine this way. I still will pursue a way to automatise it in order to not be invasive with the already declared interface types.
Does this mean that this issue #6 is obsolete? What is planed to support there?

I still will pursue a way to automatise it in order to not be invasive with the already declared interface types.

abstract class is a drop-in replacement for TS interface, you can just do text search&replace and it will work in your codebase 馃槈

abstract class is a drop-in replacement for TS interface, you can just do text search&replace and it will work in your codebase

Thank you for that info, i will do exactly that!
But again, why not to do this in here and replace it seamless? This way interfaces would work as well without anyone having to change their typings, right? This way more people and implementations could be reached. Sometimes you cant't change the entity definition.

Because interfaces doesn't exist in JS (runtime) so they are removed on TypeScript compilation step. So when the app starts, I'm not able to figure out what is the type, what fields does it have, etc. so there's no way to generate the schema with GQL types from interfaces.

The only way is to use classes and decorators to collect metadata emitted by TypeScript compiler, just the way TypeORM or class-validiator works. Or create an "offline" code generator that will read the source and comments, just like ts2gql works, but it's not the goal of TypeGraphQL.

I am closing this issue as the main problem is solved. If you want to know more details about types reflection we can discuss on gitter 馃槈
https://gitter.im/type-graphql/Lobby

Was this page helpful?
0 / 5 - 0 ratings

Related issues

MichalLytek picture MichalLytek  路  3Comments

tongtwist picture tongtwist  路  3Comments

winuxue picture winuxue  路  4Comments

oliversalzburg picture oliversalzburg  路  3Comments

robertchung97 picture robertchung97  路  3Comments