MichalLytek / type-graphql

Create GraphQL schema and resolvers with TypeScript, using classes and decorators!
https://typegraphql.com
MIT License
8.03k stars 676 forks source link

Feature: Decorate classes without @Decorators. #294

Open j opened 5 years ago

j commented 5 years ago

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.
MichalLytek commented 5 years ago

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

j commented 5 years ago

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.

MichalLytek commented 5 years ago

@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 😉

cramhead commented 5 years ago

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

j commented 5 years ago

@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.