'Nodejs + typescript how to use class models?

I am trying to learn how to use class models in nodejs and I will give you an example of what I am trying to achieve.

For example I have user.ts model :

export default class User {

    private firstname: string;
    private lastname: string;
    private email: string;
    private password: string;
    private isVerified: boolean;

    getFirstName() {
        return this.firstname;
    }

    setFirstName(val: string) {
        this.firstname = val;
    }

    getLastName() {
        return this.lastname;
    }

    setLastName(val: string) {
        this.lastname = val;
    }

    getEmail() {
        return this.email;
    }

    setEmail(val: string) {
        this.email = val;
    }

    getPassword() {
        return this.password;
    }

    setPassword(val: string) {
        this.password = val;
    }
}

And I have auth.ts route :

router.post('/login', async (req: Request, res: Response) => {
    const { error } = loginValidation(req.body);
    if (error) return res.status(400).send(error.details);

    const user = await UserModel.findOne({ email: req.body.email });
    if (!user) return res.status(400).send('Email doesn`t exist');
    if (!user.isVerified) return res.status(400).send('User is not verified, check Your email first');

    const validPass = await bcrypt.compare(req.body.password, user.password);
    if(!validPass) return res.status(400).send('Invalid password');
        const userResponse = new UserModel({
            firstname: user.firstname,
            lastname: user.lastname,
            email: user.email,
            createdAt: user.createdAt,
            updatedAt: user.updatedAt,
            isVerified: req.body.isVerified
        });

        try {
            const token = jwt.sign({_id: user._id}, process.env.TOKEN_SECRET,{ expiresIn: '8h' });
            res.header('auth-token', token);
            res.send(userResponse);
        } catch (err) {
            res.status(400).send(err);
        }
    }

I want to use my user.model for req.body, but don't know how :

Tryed :

const user: User = req.body;

user.getFirstname() - getFirstname() is not a function

user.setFirstname(req.body.firstname) <- setFirstname is not a function()

How can I attach req.body to user model ?



Solution 1:[1]

req.body returns a JSON object with an unknown type. You need a type guard to check and be sure req.body contains the value you need. You can learn more about it here https://www.typescriptlang.org/docs/handbook/advanced-types.html#type-guards-and-differentiating-types.

But firstly, you're trying to achieve getters and setters in typescript but doing it the wrong way.

So i re-wrote your User model class

export default class User {

    private _firstname: string;
    private _lastname: string;
    private _email: string;
    private _password: string;
    private _isVerified: boolean;

    get firstname() {
        return this._firstname;
    }

    set firstname(val: string) {
        this._firstname = val;
    }

    get lastname() {
        return this._lastname;
    }

    set lastname(val: string) {
        this._lastname = val;
    }

    get email() {
        return this._email;
    }

    set email(val: string) {
        this._email = val;
    }

    get password() {
        return this._password;
    }

    set password(val: string) {
        this._password = val;
    }
}

and your auth.ts route

router.post('/login', async (req: Request, res: Response) => {
    if((req.body as User).firstname){
        const user: User = req.body as User
        ...
    }
}

and you can set firstname through getter and setter by

user.firstname // get first name 
user.firstname = 'your name'

Solution 2:[2]

Why not use a constructor to model the data you receive on the request? This also works on the client-side and is useful to assure you have an object of a certain type.

What I normally do is

export default class User {

    private firstname: string;
    private lastname: string;
    private email: string;
    private password: string;
    private isVerified: boolean;

    constructor(data: Partial<User>){ // Partial<User> helps type the data
        // I'm using null or false as default value but you can change it 
        this.firstname = userData.firstname || null
        this.lastname = userData.lastname || null
        this.email = userData.email || null
        this.password = userData.password || null
        this.isVerified = userData.isVerified || false
    }

    // ... getters, setters and other methods
}

So whenever you want to model data you got from any source you may do

const user = new User(req.body)
// And now you are able to i.g.
const email = user.getEmail()

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1
Solution 2 cigien