Typescript : convert post request body to map
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']
Related videos on Youtube
Jérémy Gachon
Updated on June 04, 2022Comments
-
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 almost 5 yearsWhy have you specified
array: object
? Surely you're expecting it to be something else here? -
Jérémy Gachon almost 5 yearsI'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 almost 5 yearsThank'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 over 4 yearsOn 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 over 3 yearsIs 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 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 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 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 almost 3 yearsthere is no point of using typescript if it couldnt capture runtime errors. after all the hype is about compilation?