Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Easy way to create "output types" #493

Closed
twavv opened this issue Dec 15, 2019 · 4 comments
Closed

Easy way to create "output types" #493

twavv opened this issue Dec 15, 2019 · 4 comments
Labels
Out of scope ✖️ Proposal doesn't fit in project goals Question ❔ Not future request, proposal or bug issue

Comments

@twavv
Copy link
Contributor

twavv commented Dec 15, 2019

Is your feature request related to a problem? Please describe.
A common thing I'd like to do is create simple output types. These are types that don't have any complex resolving logic.

Describe the solution you'd like
I'd like to be able to

Describe alternatives you've considered
Currently, I have classes that look like this.

@ObjectType()
export class FooPayload {
  constructor(data: PickDataMembers<FooPayload>) {
    Object.assign(this, data);
  }

  @Field(() => Foo, { nullable: true })
  foo!: Promish<Foo | null>;

  @Field(() => ID, { nullable: false })
  mutationId!: Promish<string | null>;
}

As an aside, I have Promish<T> = Promise<T> | T and PickDataMembers<T> is a utility that picks all non-function types out of an object type (with these kinds of types it make sense to use lazy promises which aren't activated until they're .then'd).

This is fine but kind of boilerplate-y and requires all of the non-null assertions.

@twavv twavv changed the title Easy way to create "output types Easy way to create "output types" Dec 15, 2019
@MichalLytek MichalLytek added Need More Info 🤷‍♂️ Further information is requested Question ❔ Not future request, proposal or bug issue labels Dec 15, 2019
@MichalLytek
Copy link
Owner

Describe the solution you'd like
I'd like to be able to

I'm not sure what the issue is about. Your example is not a "simple output type".

This is fine but kind of boilerplate-y

I have no idea what do you expect. Even #296 won't be able to understand Promish or PickDataMembers custom generic types.

Maybe your Foo class is a rich business model and you should separate the domain from the infrastructure rather than mixing it together, hacking with Object.assign and custom utility types.

requires all of the non-null assertions.

So create an issue in TS repository to add support for Object.assign in constructor marking properties as initialized if you can't press one ! key.

@twavv
Copy link
Contributor Author

twavv commented Dec 15, 2019

I want to start by saying that I really appreciate this project. Admittedly, this is a rather minor gripe, but just something that's has come up for me a number of times.

if you can't press one ! key.

It's really not about the keystrokes. It's more about having excess boilerplate. I also just really prefer to avoid type-hacks in "product" code (e.g. avoiding type assertions, use of any, and even non-null assertions).

I have no idea what do you expect. Even #296 won't be able to understand Promish or PickDataMembers custom generic types.

I'm not so much concerned with the project's abilities around type inference (in my own code I always just use explicit types with the arrow-function thing). My example also might have been bad (I more or less just copied one that I happened to be writing and changed the name to Foo).

There have just been numerous places where I want to throw a bunch of things together. It's always as the "output" of a mutation where I just want to throw some metadata in, as well as preserve the ability to add more fields in the future in a backwards-compatible way.

type Mutation {
  createUser(...): CreateUserPayload!
}

type CreateUserPayload {
  user: User!
  clientMutationId: ID!
}

I always end up having access to the User and ID/whatever else I want to throw into the object.


The actual "solution" to this (relatively minor) gripe might not actually live in this library. I've hacked together a type-validation library (used to validate the types of JSON messages received over a WebSocket API) that looks like this:

const UserRegisterMsg = new Msg({
  name: new String(),
  email: new String().validate(checkIfIsEmailFn),
  country: new String().default(null),
});

const msgFromWire: unknown = {
  name: "Travis",
  email: "[email protected]",
};

const msg = UserRegisterMsg.parse(msgFromWire);
// msg has type
// { name: string; email: string; country: string | null }

That kind of API I think would also work for what I'm describing. But that might also just be a completely different library at that point. :^)


At any rate, feel free to close this if you think this issue is out of scope. Once again, I really appreciate this project (I'm a big fan) and thanks for the hard work on it.

@MichalLytek
Copy link
Owner

MichalLytek commented Dec 17, 2019

So to sum up, your feature request is an ability to create an instance of the class passing all the required data in constructor, in order to avoid all non-null assertion and other "hackish" things?

I'm not sure if it's in TypeGraphQL scope as some people want (to use constructor parameters #495), while others use Object.assign. So you should create your own utility to do that, like:

export class FooPayload extends Base<FooPayload> {
  @Field(() => Foo, { nullable: true })
  foo!: Promish<Foo | null>;

  @Field(() => ID, { nullable: false })
  mutationId!: Promish<string | null>;
}

const foo = new FooPayload({ foo, mutationId: 1 });

@MichalLytek
Copy link
Owner

Closing for a housekeeping purposes 🔒

@MichalLytek MichalLytek added Out of scope ✖️ Proposal doesn't fit in project goals and removed Need More Info 🤷‍♂️ Further information is requested labels Dec 27, 2019
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Out of scope ✖️ Proposal doesn't fit in project goals Question ❔ Not future request, proposal or bug issue
Projects
None yet
Development

No branches or pull requests

2 participants