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

Feature: Decorate classes without @Decorators.

Open j opened this issue 5 years ago • 5 comments

If I have existing models that are used in other apps not requiring type-graphql or graphql at all, it'd be nice to be able to decorate those without wrapping them.

Lets say I have:


/** @org/db/Doc.ts */
interface Doc {
    _id: ObjectId;
    createdAt: Date;
    updatedAt: Date;
}

abstract class Document<T extends Doc> {
    public doc: T;

    constructor(doc: T) {
        this.doc = doc;
    }

    get id(): string {
        return this.doc._id.toHexString();
    }

    // ...
}

/** @org/db/User.ts */
interface UserDocument extends Doc {
    name: string;
}

class User extends Document<UserDocument> {
    get name(): string {
        return this.doc.name;
    }
}

/** @other/graphql/___.ts */
import { ObjectTypeDecorator } from 'type-graphql';
import { User, Document } from '@org/db';

const documentDecorator = new ObjectTypeDecorator(Document);
documentDecorator.field('id');
documentDecorator.field('createdAt');
documentDecorator.field('updatedAt');

const userDecorator = new ObjectTypeDecorator(User);
userDecorator.field('name');

// can now use "User" as a type throughout.

j avatar Mar 28 '19 17:03 j

Interfaces doesn't exist at runtime, so we have absolutely no type metadata available 😞 Also in comments you can't use runtime values, so it's all string based with no type safety.

Maybe you should write your code generator that will convert the interfaces to classes with decorators? 🤔

Or just use the decorators and type-graphql shim? https://typegraphql.ml/docs/browser-usage.html

MichalLytek avatar Mar 28 '19 17:03 MichalLytek

The above code example are classes backed by interfaces. I want to use type-graphql on existing classes without having to wrap them to setup fields, etc.

j avatar Mar 28 '19 19:03 j

@j You can call the decorators manually, like in transpiled code:

class User {
  name: string;
};

ObjectType(options)(User);
Field({ nullable: true })(User.prototype, "name");

I don't want to expose utils like ObjectTypeDecorator as it's against TypeGraphQL goal to define classes with decorators to produce GraphQL schema.

In my production apps I just use the shim and the decorators on unrelated classes like RegisterFormState 😄 I can share the form state, input type shape and typeorm entity at once 😉

MichalLytek avatar Mar 29 '19 08:03 MichalLytek

Mobx has an interesting approach, https://mobx.js.org/best/decorators.html. Maybe that approach would work for you?

cramhead avatar Jul 19 '19 04:07 cramhead

@cramhead that's pretty dang cool. It's sort of what I was thinking originally.

I've since moved my models to my graph layer and with apollo federation coming soon, will be moving every model to it's specific service. Originally we had models and repositories in their own package and I wanted that library to be unaware of type-graphql and to just decorate the classes after the fact. I ended up not doing this though, but the Mobx approach looks pretty cool.

j avatar Jul 22 '19 17:07 j