Coder Social home page Coder Social logo

Comments (12)

JoseLuisGarciaOtt avatar JoseLuisGarciaOtt commented on July 20, 2024 1

Well, just reviewing it again, I found the problem.

@szokodiakos: you were right, If I let the user untyped, this works just fine. The reason why I was getting the same error ("The 'this' context of type 'User' is not assignable....") was because in the UserService class the return of getOneByField was also typed as "User". So that's why I got the same error. And since the error stack was aiming to the use of user.changeName() code-line, I couldn't realize that. So.., If Iet it untyped as well, It works just fine.

And @vinczedani , the reason why your example works great is the same: you are not typing your user with your model class.

So well, I can confidently say now that this is not a Typegoose problem. But this lets me with a big concern... because one of the main benefits of using typescript on my apps is to use my model classes in a type-safe way (well, this is obviously partial since typescript type-constraints only apply in compile-time).

Using "User & Mongoose.Document" is not only ugly (and let the code dirtier and less comprehensible) but it also breaks all my code-abstractions. For example, I use to generate service and controller classes dynamically based on generics, so I should start using "T & Mongoose.Document" everywhere, letting all my layers coupled with Mongoose. That's totally a deal breaker.

So my question is...what are you guys doing in your applications related to this? Do you let your model instances untyped? do you use "& Mongoose.Document" everywhere? Am I missing something else here?

Since this only breaks when trying to use instanceMethods, my workaround right now will be... just not using instanceMethods, so I can continue to type the model instances with the model classes.

Thanks again for your time, and I would really appreciate your insights on this.
José

from typegoose.

JoseLuisGarciaOtt avatar JoseLuisGarciaOtt commented on July 20, 2024

Is that "increment" something you add to the schema dinamically for any reason?

from typegoose.

szokodiakos avatar szokodiakos commented on July 20, 2024

Hello, can you please paste the whole User class and the code where you get the error? (possibly with screenshot of error in the IDE?)

from typegoose.

JoseLuisGarciaOtt avatar JoseLuisGarciaOtt commented on July 20, 2024

Sure thing! I created a simple example for clarity, re-compiled and the result is the same:

User model class:

import { prop, Typegoose, InstanceType, instanceMethod } from 'typegoose';
import Database from '../';

const db  = Database.getConnections();

export default class User extends Typegoose {

    @prop({ required: true })
    name: string;

    @prop({ required: true })
    email: string;

    @prop({ required: true })
    password: string;

    @instanceMethod
    public changeName(this: InstanceType<User>) {
        this.name = "blabla";
    }

}

export const UserModel = new User().getModelForClass(User, {existingMongoose: db, schemaOptions: {timestamps: true}});

FooService class:

import UserService from "../../users/service";
import User from "../../../database/model/user";

class FooService {

    public async foochangeName(email: string): Promise<User> {

        // Find user by email:
        const user: User = await UserService.getOneByField('email', email);

        user.changeName(); // << this is line 11.

        return user;
    }
}

Full stack from Webstorm Terminal when trying to compile:

info: Database - successfully connected to mongodb://localhost:27017/development
info: Database - Done..
info: Router - Start adding routes.
error: TSError: ⨯ Unable to compile TypeScript
src/api/foo-module/service.ts (11,15): The 'this' context of type 'User' is not assignable to method's 'this' of type 'InstanceType<User>'.
  Type 'User' is not assignable to type 'Document'.
    Property 'increment' is missing in type 'User'. (2684)
    at getOutput (/home/jose/WebstormProjects/project-api/node_modules/ts-node/src/index.ts:307:15)
    at /home/jose/WebstormProjects/project-api/node_modules/ts-node/src/index.ts:336:16
    at Object.compile (/home/jose/WebstormProjects/project-api/node_modules/ts-node/src/index.ts:498:11)
    at Module.m._compile (/home/jose/WebstormProjects/project-api/node_modules/ts-node/src/index.ts:392:43)
    at Module._extensions..js (module.js:580:10)
    at Object.require.extensions.(anonymous function) [as .ts] (/home/jose/WebstormProjects/project-api/node_modules/ts-node/src/index.ts:395:12)
    at Module.load (module.js:488:32)
    at tryModuleLoad (module.js:447:12)
    at Function.Module._load (module.js:439:3)
    at Module.require (module.js:498:17)
    at require (internal/module.js:20:19)
    at Object.<anonymous> (/home/jose/WebstormProjects/project-api/src/api/foo-module/controller.ts:7:1)
    at Module._compile (module.js:571:32)
    at Module.m._compile (/home/jose/WebstormProjects/project-api/node_modules/ts-node/src/index.ts:392:23)
    at Module._extensions..js (module.js:580:10)
    at Object.require.extensions.(anonymous function) [as .ts] (/home/jose/WebstormProjects/project-api/node_modules/ts-node/src/index.ts:395:12)
error: Server - There was something wrong: TSError: ⨯ Unable to compile TypeScript
src/api/foo-module/service.ts  (11,15): The 'this' context of type 'User' is not assignable to method's 'this' of type 'InstanceType<User>'.
  Type 'User' is not assignable to type 'Document'.
    Property 'increment' is missing in type 'User'. (2684)

I'm using:
Node version: 7.6.0
"hapi": "^16.4.3",
"mongoose": "^4.10.8",
"typegoose": "^3.0.0",

from typegoose.

JoseLuisGarciaOtt avatar JoseLuisGarciaOtt commented on July 20, 2024

It doesn't matter if the instance method is Async or not, Static or not, whether it receives arguments or not... always got the same error. And still have no idea what is that "increment" property that the compiler complains about... Don't see it in your code either.

from typegoose.

szokodiakos avatar szokodiakos commented on July 20, 2024

Will the error go away if you remove the explicit User typing from line

const user: User = await UserService.getOneByField('email', email);

?

that const user should not only be a User type, but if you look into the typing of Mongoose the findById, find or any other queries return User & Document type not just User.

Either you should remove the explicit typing or extend the line with the & Document. Let me know if that works.

from typegoose.

JoseLuisGarciaOtt avatar JoseLuisGarciaOtt commented on July 20, 2024

Thank you for taking the time to see this ;)

Well, if I let user untyped, the error is the same. But if I type it as User & Mongoose.Document, it compiles just fines, but.. in execution time I get this:

TypeError: user.changeName is not a function.

So I'm still believe there is something wrong in how the instance methods are being anchored to the entity. Something not related with typescript...

from typegoose.

szokodiakos avatar szokodiakos commented on July 20, 2024

No problem! Hmm, can you please post the UserService file too? Maybe there's an issue. More specifically the implementation of the getOneByField function (the whole UserService would be better though).

from typegoose.

vinczedani avatar vinczedani commented on July 20, 2024

Hi @JoseLuisGarciaOtt

I tried to reproduce your issue with the current version of typegoose (3.4.5, I advise you to upgrade, it should be backward compatibile) I used a class similar to yours.

import * as mongoose from 'mongoose';
import { prop, Typegoose, InstanceType, instanceMethod } from '../../typegoose';

export default class Foo extends Typegoose {

    @prop({ required: true })
    name: string;

    @prop({ required: true })
    email: string;

    @prop({ required: true })
    password: string;

    @instanceMethod
    public changeName(this: InstanceType<Foo>) {
        this.name = "blabla";

        return this.save();
    }

}

export const FooModel = new Foo().getModelForClass(Foo, { schemaOptions: { timestamps: true }});

Since we don't know your UserService, I was unable to mimic that. I created the following script to test the model.

const testUser = await FooModel.create({
      name: 'Tom Denem',
      email: '[email protected]',
      password: 'nagini',
    });

    const user = await FooModel.findOne({ email: '[email protected]' });

    await user.changeName();

    const changed = await FooModel.findOne({ email: '[email protected]' });

    console.log(changed);

The output of this script was the following:

{ _id: 59c39e99db563c5b6aad7897,
  updatedAt: 2017-09-21T11:12:25.574Z,
  createdAt: 2017-09-21T11:12:25.554Z,
  name: 'blabla',
  email: '[email protected]',
  password: 'nagini',
  __v: 0 }

As you can see, the name is changed and is saved in the DB. I am sure, your issue is coming from your UserService. If you can paste the GetOneByField (and the functions it uses) we can help you in the debugging process. If your problem no longer exists, please close the issue.
Cheers,
Daniel

from typegoose.

JoseLuisGarciaOtt avatar JoseLuisGarciaOtt commented on July 20, 2024

Hi @vinczedani ! Thank you too for checking this!

I'm going to make a decoupled full example for this error whenever I can, and upload it so we can get more clarity around the issue.

@szokodiakos: My service class is really not doing so much, it just performs a findOne over the Mongoose Model. I can even print the user between the getOneByField and changeName operations and check that is a valid mongoose model, well populated and everything...

But yes, since this code is partial and you can't reproduce it, let me build some full example and continue from there.

Thanks again!
José

from typegoose.

vinczedani avatar vinczedani commented on July 20, 2024

Hi @JoseLuisGarciaOtt
You are right that using "& Mongoose.Document" is ugly and not acceptable. We will try to find a solution for this issue when we have available time for the project.
In my personal applications, I always create a DataAccessLayer and it is my only layer coupled with Mongoose. The only thing returned from this layer is the data object, without the mongoose feature. Since using db related functions outside of this access layer would link additional layers to the db, not just on typescript level. So in case of a DB change. The only layer I have to switch is the DAL.

We are sorry that typegoose in its current state is not perfect for your coding style. Unfortunately we were not considering everything. @szokodiakos created typegoose to help us in our project with our coding style. Of course we made it open source so other people can use it too, and will try to make it fit every ones need, but we both have a full time job, and have limited time to work on this project.
If you have the motivation and the time to contribute to the project, we appreciate the help.

Cheers,
Daniel

from typegoose.

hasezoey avatar hasezoey commented on July 20, 2024

this can be closed, because it is fixed
with #29 (comment)


So my question is...what are you guys doing in your applications related to this? Do you let your model instances untyped? do you use "& Mongoose.Document" everywhere? Am I missing something else here?

const user: InstanceType<User> = await UserService.getOneByField('email', email); or letting it untyped

@Ben305

from typegoose.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.