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

Is mixin two more object types into another object type supported? #532

Closed
sjmittal opened this issue Feb 4, 2020 · 5 comments
Closed
Labels
Question ❔ Not future request, proposal or bug issue Wontfix ❌ This will not be worked on

Comments

@sjmittal
Copy link

sjmittal commented Feb 4, 2020

Example
I have two object types:

@ObjectType()
class A { .. }
@ObjectType()
class B { .. }

I want to create a new class C composed of fields from A and B.
Now typescript supports this and also there is a mixin example in type-graphql.
However the example is to mix only one class in some other class.

When I try to compose a new class the way typescript supports, it does not copy the decorators to the new class and the schema generated from that new class does not has the compose fields.

Any other way if this is possible?

@MichalLytek
Copy link
Owner

Any other way if this is possible?

I don't understand your question. Can you show what you've tried to do that is not working?

I want to create a new class C composed of fields from A and B.

TypeScript doesn't support multiple inheritance, you need to use mixin pattern showed in examples.

@MichalLytek MichalLytek added the Need More Info 🤷‍♂️ Further information is requested label Feb 4, 2020
@sjmittal
Copy link
Author

sjmittal commented Feb 4, 2020

So I am trying to use mixin as defined here:
https://www.typescriptlang.org/docs/handbook/mixins.html

@ObjectType()
export class C { ... }
export interface C extends A, B {}
applyMixins(C, [A, B])

However the mixed class C does not contain the fields of A, B in the final generated schema. It only contains fields defined in its own class.

Then I stumbled upon this this thread:
#359

Here it has an example of js based mixin
https://github.com/justinfagnani/mixwith.js/
If I try to use that, then it results into error like:
typeerror class extends value # object is not a constructor or null

Also as mentioned in that thread, there is no port of the same in TS.
There is another link https://mariusschulz.com/blog/mixin-classes-in-typescript
But that is essentially how can you apply different mixins to a particular class and not on how you can mix two classes.

Lastly there is an example:
https://github.com/MichalLytek/type-graphql/tree/master/examples/mixin-classes
However this example is also how you can apply mixins to a single class but does not show how two classes can be mixed into one.

Note each of the class is decorated with ObjectType

So is there any example that can show how we can mix two classes of ObjectType into a new class again of ObjectType.

@MichalLytek
Copy link
Owner

So I am trying to use mixin as defined here:
typescriptlang.org/docs/handbook/mixins.html

It's deprecated and superseded by ES6 class mixins, just because the old mixins doesn't work 😄

So is there any example that can show how we can mix two classes of ObjectType into a new class again of ObjectType.

The answer is really simple - you just can't. You need to duplicate the properties and decorator or switch to ES6 mixins, where you prefer composition of small classes, rather than inheritance of big blocks.

@MichalLytek MichalLytek added Question ❔ Not future request, proposal or bug issue Wontfix ❌ This will not be worked on and removed Need More Info 🤷‍♂️ Further information is requested labels Feb 4, 2020
@sjmittal
Copy link
Author

sjmittal commented Feb 5, 2020

So once I switch to ES6 mixins in typescript, it does not seem to be supported.
I was using the reference as here:
https://github.com/justinfagnani/mixwith.js/

I have also checked this PR
microsoft/TypeScript#13743

Here again if you see the example it is adding mixin(s) to single class.
Like to class Point and class Person it has added mixin Tagged.
And in this mixin additional properties or methods are defined.

However is we just use the same example and imagine that class Point and class Person are decorated with ObjectType and if you want to mix these two classes to create a new class PersonPoint again decorated with ObjectType. Is this something possible or as you mentioned only way is to duplicate properties and decorator in the mixin.

@andersoncscz
Copy link

Hi guys.

I'm using TypeORM and I'm isolationg TypeORM decorators in my entities (User, GroupMember). For TypeGraphQL fields I'm using UserFields GroupMemberFields which are classes using just TypeGraphQL decorators. I prefered to used this approach instead of keeping all decorators in my TypeORM entities. As mentioned by @MichalLytek I didn't know that this feature typescriptlang.org/docs/handbook/mixins.html was deprecated, didn't find this information in this link.

I achieved the desired schema generated by doing:

class mixed: GroupMemberUser.ts

// *** TypeORM entities ***
import {GroupMember} from '@/src/db/entity/GroupMember'
import {User} from '@/src/db/entity/User'

// *** TypeGraphQL classes with @InterfaceType() ***
import {GroupMemberFields} from '@/src/graphql/fields/GroupMemberFields'
import {UserFields} from '@/src/graphql/fields/UserFields'

import {applyMixins} from '@/src/helper'
import {ObjectType, Field} from 'type-graphql'

export interface GroupMemberUser extends User, GroupMember {}

@ObjectType({implements: [UserFields, GroupMemberFields]})
export class GroupMemberUser {
  @Field()
  particularField: string
}

applyMixins(GroupMemberUser, [User, GroupMember])

Group.ts (TypeORM entity)

@Entity()
@ObjectType({implements: GroupFields})
export class Group extends BaseEntity implements GroupFields {
   ...

  @Field(type => [GroupMemberUser]) // Here is where I'm using the mixed class.
  @ManyToMany(type => GroupMember)
  @JoinTable()
  members: GroupMember[]
}

The schema generated:

type GroupMemberUser implements UserFields & GroupMemberFields {
  // UserFields properties
  name: String!
  email: String!
  phone: String
  profilePictureUrl: String
  accountType: UserAccountType!
  accountExpirationDate: DateTime!

  // GroupMemberFields properties
  isOwner: Boolean!
  isAdmin: Boolean!

  // Particular property of class mixed.
  particularField: String!
}

Hope this helped.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Question ❔ Not future request, proposal or bug issue Wontfix ❌ This will not be worked on
Projects
None yet
Development

No branches or pull requests

3 participants