TypeScript给出了一个关于“没有与此调用匹配的重载,最后一个重载给出了以下错误”的LONG错误,

dzhpxtsq  于 2023-01-10  发布在  TypeScript
关注(0)|答案(1)|浏览(2067)

我正在编写一个基于Jason Watmore的用户认证样板的用户认证中间件。
我期望的结果是这段代码“正常工作”,因为它是从另一个项目复制来的,在那里它确实是这样做的。
我的实际结果是得到了这条很长的错误消息:

(alias) authorize(roles?: Role[]): ({
    (req: express.Request<ParamsDictionary, any, any, QueryString.ParsedQs, Record<string, any>>, res: express.Response<...>, next: express.NextFunction): Promise<...>;
    unless: (options: Params) => {
        ...;
    };
} | ((request: RequestWithUser, res: express.Response<...>, next: express.NextFunction) => Promise<...>))[]
import authorize
No overload matches this call.
  The last overload gave the following error.
    Argument of type '({ (req: Request<ParamsDictionary, any, any, ParsedQs, Record<string, any>>, res: Response<any, Record<string, any>>, next: NextFunction): Promise<...>; unless: (options: Params) => { ...; }; } | ((request: RequestWithUser, res: Response<...>, next: NextFunction) => Promise<...>))[]' is not assignable to parameter of type 'RequestHandlerParams<ParamsDictionary, any, any, ParsedQs, Record<string, any>>'.
      Type '({ (req: Request<ParamsDictionary, any, any, ParsedQs, Record<string, any>>, res: Response<any, Record<string, any>>, next: NextFunction): Promise<...>; unless: (options: Params) => { ...; }; } | ((request: RequestWithUser, res: Response<...>, next: NextFunction) => Promise<...>))[]' is not assignable to type '(ErrorRequestHandler<ParamsDictionary, any, any, ParsedQs, Record<string, any>> | RequestHandler<ParamsDictionary, any, any, ParsedQs, Record<...>>)[]'.
        Type '{ (req: Request<ParamsDictionary, any, any, ParsedQs, Record<string, any>>, res: Response<any, Record<string, any>>, next: NextFunction): Promise<...>; unless: (options: Params) => { ...; }; } | ((request: RequestWithUser, res: Response<...>, next: NextFunction) => Promise<...>)' is not assignable to type 'ErrorRequestHandler<ParamsDictionary, any, any, ParsedQs, Record<string, any>> | RequestHandler<ParamsDictionary, any, any, ParsedQs, Record<...>>'.
          Type '(request: RequestWithUser, res: Response, next: NextFunction) => Promise<Response<any, Record<string, any>> | undefined>' is not assignable to type 'ErrorRequestHandler<ParamsDictionary, any, any, ParsedQs, Record<string, any>> | RequestHandler<ParamsDictionary, any, any, ParsedQs, Record<...>>'.
            Type '(request: RequestWithUser, res: Response, next: NextFunction) => Promise<Response<any, Record<string, any>> | undefined>' is not assignable to type 'ErrorRequestHandler<ParamsDictionary, any, any, ParsedQs, Record<string, any>>'.
              Types of parameters 'res' and 'req' are incompatible.
                Type 'Request<ParamsDictionary, any, any, ParsedQs, Record<string, any>>' is missing the following properties from type 'Response<any, Record<string, any>>': status, sendStatus, links, send, and 53 more.ts(2769)
index.d.ts(163, 5): The last overload is declared here.
No quick fixes available

下面是违规代码

function authorize(roles: Role[] = []) {
    if (typeof roles === "string") {
        roles = [roles];
    }

    return [
        jwt({
            secret, // authenticate JWT token and attach user to request object (req.user)
            algorithms: ["HS256"],
        }),
// problem is caused here with "RequestWithUser"
        async (request: RequestWithUser, res: Response, next: NextFunction) => {
            const acctInfo = request.auth;
            if (acctInfo?.acctId === undefined) {
                return res.status(401).json({ message: "Unauthorized" });
            }
            request.user = {
                acctId: acctInfo.acctId,
                role: "", // temp to satisfy ts
            };
            const account: Account | null = await acctDAO.getAccountById(acctInfo.acctId);
            if (!account) return res.status(401).json({ message: "Unauthorized" });
            const refreshTokens = await rtDAO.getAllRefreshTokensForAccount(account.acctId);

            const validRoles = Object.values(Role);
            const acctRole: Role = account.role as Role;
            const rolesFoundOnRequest = roles.length;
            if (rolesFoundOnRequest && !validRoles.includes(acctRole)) {
                return res.status(401).json({ message: "Unauthorized" });
            }

            request.user.role = account.role;
            request.user.ownsToken = (token: string) => !!refreshTokens.find((x: any) => x.token === token);
            next();
        },
    ];
}

export default authorize;

当我将RequestWithUser改回Request时,错误消失了,但这不起作用,因为中间件的其余部分将出现预期错误类型的TS错误。
如您所见,RequestWithUser只是一个扩展的Express Request

export interface RequestWithUser extends Request {
    user?: {
        role: string;
        ownsToken?: Function;
        acctId: number;
    };
    auth?: {
        sub: any;
        acctId: number;
    };
}

我完全不明白这个错误信息,它似乎是在说“express将把这个传递给ErrorRequestHandler,形状不合适”,但我完全不清楚发生了什么。
编辑:所以很明显我应该告诉你错误出现在哪里。2下面的路由都是错误出现在哪里的例子。

this.router.get("/", authorize([Role.Admin]), this.getAllAccounts);
        this.router.get("/:id", authorize(), this.getAccountById);
        this.router.post("/", authorize([Role.Admin]), createAccountSchema, this.createAccount);
        this.router.put("/:id", authorize(), updateRoleSchema, this.updateAccount);
46qrfjad

46qrfjad1#

RequestWithUser只是扩展的Express Request
不要创建一个特定的接口(即使它扩展了Request),而是使用声明合并来 * 扩充 * 实际的Request接口本身。
问题不在于运行时代码,而在于额外的类型。
错误消息本身确实具有误导性,但它是由不同的第一个参数类型直接导致的。
因为它不匹配通常的Request类型,TypeScript尝试推断一个不同的函数重载,并以一个应该接受普通RequestHandler和ErrorRequestHandler的混合的重载结束...但是您的函数不能同时处理这两个类型,因此出现了错误消息。

相关问题