首页 > 解决方案 > 打字稿无法识别快速会话中的用户类型

问题描述

我正在从数据库中检索用户对象并将其设置在快速会话中:

export const postLogin = async (
    request: Request,
    response: Response,
    next: NextFunction
): Promise<void> => {
    try {
        request.session.user = await UserModel.findById('6127bd9d204a47128947a07d').orFail().exec()
        response.redirect('/')
    } catch (error) {
        next(error)
    }
}

然后我在用户对象上调用 Mongoose 方法populate()来获取与之关联的购物车:

export const getCart = async (
    request: Request,
    response: Response,
    next: NextFunction
): Promise<void> => {
    try {
        const userWithCartProducts = await request.session.user
            .populate('cart.items.productId')
            .execPopulate()
    } catch (error) {
        next(error)
    }
}

但在这里我得到一个错误:TypeError: request.session.user.populate is not a function

我在 express-session 上定义了自定义用户类型,如下所示:

declare module 'express-session' {
    interface SessionData {
        user?: DocumentType<User>
    }
}

正如您在上面的定义中看到的那样user,我正在使用,DocumentType<User>因为我正在使用Typegoose键入我的模型。我不确定这是否是 Typegoose 的做法。

我究竟做错了什么?任何输入将不胜感激。

标签: typescriptmongodbexpressmongoosetypegoose

解决方案


问题是user对象中的session对象是由MongoDBStore. MongoDBStore不知道 Typegoose 中定义的模型User,因此,当它从会话数据库中获取数据时,它只获取原始数据,而不是 Typegoose 模型中定义的方法。

所以,为了解决这个问题,当一个新的请求进来时,在初始化快速会话之后,在中间件中,我们需要从数据库中获取一次用户并放入request对象,如下所示:

app.use(initializeUser)

export const initializeUser = async (request: Request, response: Response, next: NextFunction): Promise<void> => {
    try {
        request.user = await User.findById(request.session.user._id).orFail().exec()
        next()
    } catch (error) {
        next(error)
    }
}

对于 Typegoose,定义User模型Request如下:

declare global {
    declare namespace Express {
        export interface Request {
            user?: DocumentType<User>
        }
    }
}

如问题中所述,在login路由中,即使我们将user对象存储在 中session,请求也会在那里终止,并且会话(连同user对象)被保存到数据库中。但是下一次request进来时,不知道模型和Typegoose定义的方法的人会检索到user可用的对象。所以,这就是我们解决这个问题的方法。同样的解决方案也适用于带有 Mongoose 的 Javascript。sessionMongoDBStoreUser


推荐阅读