Typescript : convert post request body to map

12,138

Solution 1

I have a different suggestion which I find nice in typescript and started using intensively. Instead of creating a class for your user you can define it as an interface.

export interface User { 
 email: string, 
 password: string, 
 firstName: string,
 lastName: string, 
 // etc 
}

and then simply do:

const user = req.body.user as User; 

It's faster and cleaner to type as long as you use these just for creating domain model objects with no business logic.

EDIT:

IF you need to stick with class then try using any type.

 export class user { 
 constructor(userDto: any) { 
   // your logic
   } 
 }


 new User(req.body.user); 

Solution 2

I'm particularly likes Dan's solution, is clean and also is fast. But if he ToMap function is need it, you can consider use https://lodash.com/ is a very handy library, helps with arrays, object mappings, deep cloning .

Regards

PD: you also can use indexer secondaryDarkColor =array.['secondaryDarkColor']

Share:
12,138

Related videos on Youtube

Jérémy Gachon
Author by

Jérémy Gachon

Updated on June 04, 2022

Comments

  • Jérémy Gachon
    Jérémy Gachon almost 2 years

    I'm programming an rest api with node js and typescript and for create user, my api recieve a json post :

    import {Request, Response, Router} from "express";
    import {User} from '../../../models/user.model';
    import {createUser} from '../../../factories/user.factory';
    
    export default [
            {
                path: "/api/v1/user/create",
                method: "post",
                handler: [
                    async (req: Request, res: Response) => {
                        createUser(new User(req.body.user));
                        res.status(200).send(req.body);
                    }
                ]
            }
        ];
    

    For exemple, I send that :

    {
        "user": {
            "email": "[email protected]",
            "password": "12345678",
            "firstName": "Jérémy"
            }
        }
    

    I would like create an object "User" with the object req.body.user :

    import {Timestamp} from './timestamp.model';
    
    export class User {
        id: bigint | undefined;
        email: string | undefined;
        password: string | undefined;
        firstName: string | undefined;
        lastName: string | undefined;
        pseudo: string | undefined;
        birthDate: Timestamp | undefined;
        lastEditDate: Timestamp | undefined;
        creationDate: Timestamp | undefined;
        googleAuthToken: string | undefined;
        language: string | undefined;
        profileAvatarUrl: string | undefined;
        profileBannerUrl: string | undefined;
        primaryLightColor: string | undefined;
        secondaryLightColor: string | undefined;
        primaryDarkColor: string | undefined;
        secondaryDarkColor: string | undefined;
    
        constructor(array: object) {
            console.log(array);
            // @ts-ignore
            console.log(array.gg);
            // @ts-ignore
            this.id = array.id;
            // @ts-ignore
            this.email = array.email;
            // @ts-ignore
            this.password = array.password;
            // @ts-ignore
            this.firstName = array.firstName;
            // @ts-ignore
            this.lastName = array.lastName;
            // @ts-ignore
            this.pseudo = array.pseudo;
            // @ts-ignore
            this.birthDate = array.birthDate;
            // @ts-ignore
            this.lastEditDate = array.lastEditDate;
            // @ts-ignore
            this.creationDate = array.creationDate;
            // @ts-ignore
            this.googleAuthToken = array.googleAuthToken;
            // @ts-ignore
            this.language = array.language;
            // @ts-ignore
            this.profileAvatarUrl = array.profileAvatarUrl;
            // @ts-ignore
            this.profileBannerUrl = array.profileBannerUrl;
            // @ts-ignore
            this.primaryLightColor = array.primaryLightColor;
            // @ts-ignore
            this.secondaryLightColor = array.secondaryLightColor;
            // @ts-ignore
            this.primaryDarkColor = array.primaryDarkColor;
            // @ts-ignore
            this.secondaryDarkColor = array.secondaryDarkColor;
            // @ts-ignore
        }
    
         toMap() {
            return {
                "id": this.id,
                "email": this.email,
                "firstName": this.firstName,
                "lastName": this.lastName,
                "pseudo": this.pseudo,
                "profileAvatarUrl": this.profileAvatarUrl,
                "birthDate": this.birthDate,
                "lastEditDate": this.lastEditDate,
                "creationDate": this.creationDate,
                "language": this.language,
                "googleAuthToken": this.googleAuthToken,
                "profileBannerUrl": this.profileBannerUrl,
                "primaryLightColor": this.primaryLightColor,
                "secondaryLightColor": this.secondaryLightColor,
                "primaryDarkColor": this.primaryDarkColor,
                "secondaryDarkColor": this.secondaryDarkColor,
            }
        }
    
    }
    

    I have put all this "// @ts-ignore" because if not , I've this error :

    src/models/user.model.ts(27,25): error TS2339: Property 'id' does not exist on type 'object'. src/models/user.model.ts(28,32): error TS2339: Property 'email' does not exist on type 'object'. src/models/user.model.ts(29,35): error TS2339: Property 'password' does not exist on type 'object'. src/models/user.model.ts(30,36): error TS2339: Property 'firstName' does not exist on type 'object'. src/models/user.model.ts(31,35): error TS2339: Property 'lastName' does not exist on type 'object'.

    My question is : How correctly make my class user for not have to put all this "// @ts-ignore" ?

    Thank's in advance. Jérémy.

    • Etheryte
      Etheryte almost 5 years
      Why have you specified array: object? Surely you're expecting it to be something else here?
    • Jérémy Gachon
      Jérémy Gachon almost 5 years
      I've test with Array<string> and Map<string, any> but with that I cant access to my values event with ts_ignore. And i've add that to my code : console.log(typeof req.body.user); and that print object.
  • Jérémy Gachon
    Jérémy Gachon almost 5 years
    Thank's, I now this soluce, but I've to put functions in my class user like : user.toMap(); and for that, I've to have a class :
  • ontek
    ontek over 4 years
    On the type assertion in the first part of your reply, it is worth pointing out that this only tells the compiler that the input is a User. It doesn't enforce anything about the input, you are still wide open to runtime errors in the event that your payload does not conform to a User type. In other words, you still need to validate that the input actually is of type User.
  • Trevor
    Trevor over 3 years
    Is there a way to do this where it only selects the fields that match the interface/class? I like how concise it is, but don't want it to grab other fields from the request body. Just the ones that match properties on the class.
  • lordvcs
    lordvcs over 3 years
    @ontek Is there any way to fix this so that it will throw an error if req.body doesnt confirm to the type?
  • ontek
    ontek over 3 years
    @lordvcs not really. To conceptualize why this is, you have to consider that anything that isn't JavaScript doesn't make it into the compiled output. In other words, interfaces are for the compiler, not the runtime. As far as reusing the interface for validation, you'd need to use something like this github.com/gristlabs/ts-interface-checker (haven't used it YMMV). Something that does seem promising is this github.com/joiful-ts/joiful, but that's using TS generators to annotate a class and put all of your validations in one place.
  • ontek
    ontek over 3 years
    @lordvcs (cont) For me, usually I just write a method called createUser that accepts a POJO, validates and returns an object that conforms to the interface. This keeps the compiler happy, but it does leave a lot of boilerplate.
  • ajay
    ajay almost 3 years
    there is no point of using typescript if it couldnt capture runtime errors. after all the hype is about compilation?