1
votes

Typographie: convertir le corps de la demande de publication en carte

Je suis en train de programmer une API de repos avec node js et dactylographié et pour create user, mon api reçoit un post json:

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,
        }
    }

}

Par exemple, je l'envoie:

XXX

Je voudrais créer un objet "User" avec l'objet req.body.user:

{
    "user": {
        "email": "test@gmail.com",
        "password": "12345678",
        "firstName": "Jérémy"
        }
    }

J'ai mis tout ça "/ / @ ts-ignore "car sinon, j'ai cette erreur:

src / models / user.model.ts (27,25): erreur TS2339: la propriété 'id' ne fonctionne pas existent sur le type 'objet'. src / models / user.model.ts (28,32): erreur TS2339: La propriété 'email' n'existe pas sur le type 'objet'. src / models / user.model.ts (29,35): erreur TS2339: propriété 'mot de passe' n'existe pas sur le type 'objet'. src / models / user.model.ts (30,36): erreur TS2339: la propriété «firstName» n'existe pas sur le type «objet». src / models / user.model.ts (31,35): erreur TS2339: propriété 'lastName' n'existe pas sur le type 'objet'.

Ma question est: comment faire correctement mon utilisateur de classe pour ne pas avoir à mettre tout cela "// @ ts-ignore"?

Merci d'avance. Jérémy.


2 commentaires

Pourquoi avez-vous spécifié array: object ? Vous vous attendez sûrement à ce que ce soit autre chose ici?


J'ai testé avec Array et Map mais avec cela, je ne peux pas accéder à mon événement de valeurs avec ts_ignore. Et j'ai ajouté cela à mon code: console.log (typeof req.body.user); et cet objet d'impression.


3 Réponses :


8
votes

J'ai une suggestion différente que je trouve agréable en tapuscrit et que j'ai commencé à utiliser de manière intensive. Au lieu de créer une classe pour votre utilisateur, vous pouvez la définir comme une interface.

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


 new User(req.body.user); 

puis faites simplement:

const user = req.body.user as User; 

C'est plus rapide et plus propre à taper tant que vous les utilisez uniquement pour créer des objets de modèle de domaine sans logique métier.

MODIFIER:

SI vous devez vous en tenir à la classe, essayez d'utiliser n'importe quel type.

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


6 commentaires

Merci, j'ai maintenant cette solution, mais je dois mettre des fonctions dans ma classe user comme: user.toMap (); et pour cela, je dois avoir une classe:


Concernant l'assertion de type dans la première partie de votre réponse, il convient de souligner que cela indique uniquement au compilateur que l'entrée est un utilisateur. Il n'applique rien sur l'entrée, vous êtes toujours ouvert aux erreurs d'exécution dans le cas où votre charge utile ne serait pas conforme à un type d'utilisateur. En d'autres termes, vous devez toujours valider que l'entrée est réellement de type User.


Existe-t-il un moyen de le faire où il sélectionne uniquement les champs qui correspondent à l'interface / la classe? J'aime sa concision, mais je ne veux pas qu'il récupère d'autres champs du corps de la requête. Juste ceux qui correspondent aux propriétés de la classe.


@ontek Existe-t-il un moyen de résoudre ce problème afin qu'il génère une erreur si req.body ne confirme pas le type?


@lordvcs pas vraiment. Pour conceptualiser pourquoi, vous devez considérer que tout ce qui n'est pas JavaScript ne fait pas partie de la sortie compilée. En d'autres termes, les interfaces sont destinées au compilateur et non à l'exécution. En ce qui concerne la réutilisation de l'interface pour la validation, vous devez utiliser quelque chose comme ça github.com/ gristlabs / ts-interface-checker (je ne l'ai pas utilisé YMMV). Quelque chose qui semble prometteur est ce github.com/joiful-ts/joiful , mais cela utilise Générateurs TS pour annoter une classe et mettre toutes vos validations en un seul endroit.


@lordvcs (cont) Pour moi, en général, j'écris simplement une méthode appelée createUser qui accepte un POJO, valide et renvoie un objet conforme à l'interface. Cela rend le compilateur heureux, mais cela laisse beaucoup de passe-partout.



1
votes

J'aime particulièrement la solution de Dan, elle est propre et rapide. Mais si la fonction ToMap en a besoin, vous pouvez envisager d'utiliser https://lodash.com/ est un outil très pratique bibliothèque, aide avec les tableaux, les mappages d'objets, le clonage en profondeur.

Cordialement

PD: vous pouvez également utiliser l'indexeur secondaryDarkColor = array. ['secondaryDarkColor']


0 commentaires

0
votes

Il y a quelques points qui mériteraient d'être clarifiés et qui obscurcissent la solution de celui-ci.

La première chose est que votre méthode toMap est quelque peu inutile, en tant que classe ES6 est un modèle pour créer un objet a>, donc la création d'une instance de votre classe avec le mot-clé new vous rend un objet, et la méthode toMap ne renvoie pas réellement un User code> objet même s'il est conforme au type. Si vous souhaitez renvoyer un User , vous devez modifier votre signature pour lire:

class User {
  constructor(
    public id?: string, // or private
    public email?: string
  ) {}
}

const user = new User("abc123", "this@example.com")

console.log(user)

# >>> User: { "id": "abc123", "email": "this@example.com" }

Ceci informe le compilateur que vous avez l'intention de renvoie un User , sinon, le compilateur voit juste l'objet et en déduit qu'il s'agit d'un objet concret avec les propriétés que vous avez définies.

De plus, votre constructeur a la signature suivante :

constructor(array: object) { ... }

D'une part, appeler votre variable array est lié à la confusion sur la route, car quelqu'un lisant votre code, ils supposeront qu'ils travaillent avec un tableau, mais que vous l'avez tapé comme object .

En ce qui concerne les erreurs de type, vous les obtenez parce que de TypeScript objet car il représente le type non primitif , et n'a en fait aucune propriété du tout, donc lorsque vous essayez d'y accéder, le compilateur ne peut pas y accéder.

Avec votre code, vous pouvez remplacer object par any et il compilerait très probablement, mais je ne pense pas que vous voudriez cela.

Il y a une méthode beaucoup plus concise pour accomplir ce que vous recherchez, vous pouvez réellement définir vos attributs et leurs types en les définissant dans le constructeur, comme ceci:

toMap(): User { ... }

Notez également que vous pouvez utiliser un point d'interrogation pour indiquer qu'une entrée est facultative.

Si vous voulez accepter un objet json comme entrée au lieu de tout mettre dans votre constructeur, vous pouvez toujours définir une méthode statique sur la classe qui accepte un any comme entrée et renvoie une instance de la classe.

Voir violon par exemple.


0 commentaires