You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

TypeScript无法识别type-graphql useMiddleware的类型校验问题

你遇到的是TypeScript无法识别中间件已确保req.session.userId存在的类型安全问题,除了if判断、//@ts-ignore和类型断言,还有以下几种更优雅的解决方案:

1. 使用自定义参数装饰器封装用户ID获取逻辑

创建一个@UserId()装饰器,既封装从session中提取用户ID的逻辑,又通过运行时检查确保ID存在,同时让TypeScript自动推导类型为非可选值。

// 自定义装饰器
import { createParamDecorator } from 'type-graphql';
import { MyContext } from 'src/types';

export const UserId = createParamDecorator<MyContext>(({ context }) => {
  const userId = context.req.session.userId;
  if (!userId) {
    throw new Error('Not authenticated');
  }
  return userId;
});

在resolver中使用:

@Mutation(() => PostType)
@UseMiddleware(isAuth)
async createPost(
       @Arg('title') title: string,
       @Arg('text') text: string,
       @Ctx() { prisma }: MyContext,
       @UserId() authorId: string // 类型自动为string,无undefined提示
): Promise<PostType> {
       return await prisma.post.create({
       data: {
        title,
        text,
        authorId,
       },
        });
}

2. 拆分Context类型,区分已认证与未认证场景

定义一个AuthenticatedContext类型,继承基础MyContext并将req.session.userId设为非可选,然后在中间件中转换上下文类型,确保经过认证的resolver使用正确的类型。

// 定义已认证上下文类型
import { MyContext } from 'src/types';

export type AuthenticatedContext = Omit<MyContext, 'req'> & {
  req: MyContext['req'] & { session: { userId: string } };
};

// 修改isAuth中间件,返回已认证上下文
export const isAuth: MiddlewareFn<MyContext, AuthenticatedContext> = ({ context }, next) => {
    if (context.req.session.userId === undefined) {
        throw new Error('Not authenticated');
    }
    // 转换上下文类型
    return next({ 
        ...context, 
        req: context.req as AuthenticatedContext['req'] 
    });
};

在resolver中指定上下文类型:

@Mutation(() => PostType)
@UseMiddleware(isAuth)
async createPost(
       @Arg('title') title: string,
       @Arg('text') text: string,
       @Ctx() { prisma, req }: AuthenticatedContext // 使用已认证上下文类型
): Promise<PostType> {
       return await prisma.post.create({
       data: {
        title,
        text,
        authorId: req.session.userId, // TS不再提示undefined
       },
        });
}

3. 编写类型断言函数增强类型安全

创建一个断言函数,在运行时验证用户ID存在的同时,告诉TypeScriptreq.session.userId是非可选的,比单纯的类型断言多一层运行时保障。

// 类型断言函数
import { MyContext } from 'src/types';

export function assertAuthenticated(req: MyContext['req']): asserts req is typeof req & { session: { userId: string } } {
  if (req.session.userId === undefined) {
    throw new Error('Not authenticated');
  }
}

在resolver中调用:

@Mutation(() => PostType)
@UseMiddleware(isAuth)
async createPost(
       @Arg('title') title: string,
       @Arg('text') text: string,
       @Ctx() { prisma, req }: MyContext
): Promise<PostType> {
       assertAuthenticated(req); // 调用后TS识别userId为非可选
       return await prisma.post.create({
       data: {
        title,
        text,
        authorId: req.session.userId,
       },
        });
}

内容的提问来源于stack exchange,提问作者blackEagle

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.29 19:02:47