打字稿:将帖子请求正文转换为地图

时间:2019-05-01 13:59:45

标签: arrays node.js json typescript post

我正在用节点js和打字稿编写一个REST API,对于创建用户,我的api收到json帖子:

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);
                }
            ]
        }
    ];

例如,我发送:

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

我想用对象req.body.user创建一个对象“ 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,
        }
    }

}

我把所有这些“ // @ ts-ignore”放进去,因为如果没有,我就遇到了这个错误:

  

src / models / user.model.ts(27,25):错误TS2339:属性“ id”没有   存在于“对象”类型上。 src / models / user.model.ts(28,32):错误TS2339:   属性“电子邮件”在类型“对象”上不存在。   src / models / user.model.ts(29,35):错误TS2339:属性“密码”   类型'object'上不存在。 src / models / user.model.ts(30,36):   错误TS2339:类型“对象”上不存在属性“名字”。   src / models / user.model.ts(31,35):错误TS2339:属性“ lastName”   类型'object'上不存在。

我的问题是:如何正确地使班级用户不必将所有这些“ // @ ts-ignore”放?

先谢谢您。 杰里米。

3 个答案:

答案 0 :(得分:1)

我有一个不同的建议,我在打字稿中发现很好,并开始大量使用它。无需为您的用户创建类,您可以将其定义为接口。

^

然后简单地做:

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

只要将它们用于创建没有业务逻辑的域模型对象,键入它们的速度就会更快,更干净。

编辑:

如果您需要坚持上课,然后尝试使用 any  类型。

const user = req.body.user as User; 

答案 1 :(得分:1)

我特别喜欢Dan的解决方案,既干净又快速。但是,如果他需要ToMap函数,可以考虑使用https://lodash.com/是一个非常方便的库,可以帮助处理数组,对象映射和深度克隆。

致谢

PD:您也可以使用索引器secondaryDarkColor =array.['secondaryDarkColor']

答案 2 :(得分:0)

有些事情可能需要清除,使解决方案变得模糊。

第一件事是您的toMap方法是不必要的,因为ES6类template for creating an object,所以用{{1}创建类的实例}关键字为您提供了一个对象,即使new方法符合类型,它实际上也不会返回toMap对象。如果您想返回User,则需要将签名修改为:

User

这会通知编译器您打算返回toMap(): User { ... } ,否则,编译器只会看到该对象并将其推断为具有您定义的属性的具体对象。

此外,您的构造函数具有以下签名:

User

例如,调用变量constructor(array: object) { ... } 势必会引起混乱,对于读取代码的人,他们会假定他们正在使用数组,但是您将其键入为array

就类型错误而言,您之所以得到它们,是因为TypeScript的object是因为它代表non-primitive type,实际上根本没有任何属性,因此当您尝试访问一个类型错误时,编译器无法访问它。

使用您当前的代码,您可以将object替换为object,并且很可能会进行编译,但是我认为您不希望这样做。

有一种更简洁的方法可以完成您要执行的操作,您实际上可以通过在构造函数中进行设置来定义属性及其类型,如下所示:

any

还请注意,您可以使用问号表示输入是可选的。

如果要接受json对象作为输入,而不是将所有内容都放入构造函数中,则可以始终在类上定义一个静态方法,该方法接受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" } 作为输入并返回该类的实例

例如,请参见fiddle