# `src/shared/types` 规范核查报告 > 核查日期:2026-06-18 > 核查范围:`src/shared/types/` 目录下所有前后端文件 > 依据文档:项目规则、编码规范、架构影响地图 004、架构数据 005 > 应用技能:`vercel-react-best-practices`、`web-artifacts-builder`、`web-design-guidelines` --- ## 一、核查文件清单 | 文件 | 行数 | 类型 | 用途 | |------|------|------|------| | [action-state.ts](../src/shared/types/action-state.ts) | 5 | 类型定义 | Server Action 统一返回类型 | | [action-state.test.ts](../src/shared/types/action-state.test.ts) | 33 | 单元测试 | ActionState 类型测试 | | [permissions.ts](../src/shared/types/permissions.ts) | 114 | 类型定义+常量 | 权限点常量、Permission/DataScope/AuthContext 类型 | --- ## 二、违规问题清单 ### 2.1 action-state.ts — 严重度:高 #### BUG-A01:Prettier 配置违规(使用分号) - **位置**:`src/shared/types/action-state.ts:1-5` - **问题**:文件使用分号(`;`)结尾,但项目 `.prettierrc` 配置 `"semi": false`,应移除所有分号 - **现状**: ```typescript export type ActionState = { success: boolean; message?: string; errors?: Record; data?: T; }; ``` - **改进建议**:移除所有分号,与 `permissions.ts`、`action-state.test.ts` 保持一致 #### BUG-A02:缺少 JSDoc 文档注释 - **位置**:`src/shared/types/action-state.ts:1` - **问题**:`ActionState` 类型缺少 JSDoc 注释,未说明类型用途、泛型参数、各字段含义 - **规范依据**:编码规范 5.4「必须编写 JSDoc」 - **改进建议**:补充类型级 JSDoc,说明 `@template T`、各 property 语义 --- ### 2.2 permissions.ts — 严重度:高 #### BUG-P01:权限点命名不一致(下划线 vs 驼峰) - **位置**:`src/shared/types/permissions.ts:91` - **问题**:`EXAM_PROCTOR_READ: "exam:proctor_read"` 使用下划线分隔,而其他 READ 权限均使用单词形式(如 `exam:read`、`question:read`) - **改进建议**:统一为 `exam:proctor:read`(嵌套资源用冒号分隔) #### BUG-P02:`Permissions` 常量缺少 `satisfies` 类型约束 - **位置**:`src/shared/types/permissions.ts:4-96` - **问题**:使用 `as const` 但未用 `satisfies` 验证所有值均为字符串,无法在编译期捕获值类型错误 - **规范依据**:编码规范 4.2.3「可用 `satisfies` 保持类型推导」 - **改进建议**:`as const satisfies Record` #### BUG-P03:`AuthContext.roles` 类型过于宽松 - **位置**:`src/shared/types/permissions.ts:111` - **问题**:`roles: string[]` 允许任意字符串,但项目角色是有限集合(admin/teacher/student/parent/grade_head/teaching_head) - **影响**:拼写错误(如 `"techer"`)无法在编译期发现;与 `proxy.ts:21` 中 `resolveDefaultPath(roles: string[])` 的硬编码角色判断形成隐患 - **改进建议**:定义 `Role` 联合类型,`AuthContext.roles` 改为 `Role[]`,`ROLE_PERMISSIONS` 改为 `Record` #### BUG-P04:`DataScope` 缺少 JSDoc 与字段说明 - **位置**:`src/shared/types/permissions.ts:101-107` - **问题**:6 种数据范围类型未说明各自语义、适用角色、使用场景 - **改进建议**:补充类型级 JSDoc,说明每种 `type` 的适用角色与语义 #### BUG-P05:`AuthContext` 接口缺少 JSDoc - **位置**:`src/shared/types/permissions.ts:109-114` - **问题**:接口无文档说明,使用者无法快速理解字段语义 - **规范依据**:编码规范 5.4 - **改进建议**:补充接口级 JSDoc,说明「认证上下文,由 `getAuthContext()` 返回,贯穿所有 Server Action」 #### BUG-P06:`DataScope.class_members` 缺少关联数据 - **位置**:`src/shared/types/permissions.ts:104` - **问题**:`{ type: "class_members" }` 不携带 classIds,导致 data-access 层每次都需要额外查询学生所在班级,存在 N+1 查询风险 - **影响**:`exams/data-access.ts`、`homework/data-access.ts` 等模块在过滤时需重复查询 `classMembers` 表 - **改进建议**:在 `resolveDataScope` 中预查并携带 classIds:`{ type: "class_members"; classIds: string[] }` --- ### 2.3 action-state.test.ts — 严重度:中 #### BUG-T01:测试覆盖率不足 - **位置**:`src/shared/types/action-state.test.ts:4-33` - **问题**:仅测试 3 种基本状态,缺少以下场景: 1. `errors` 字段包含多个字段、每个字段多条错误消息 2. `data` 为 `null`、`undefined`、`0`、`""` 等 falsy 值时的行为 3. 同时存在 `errors` 和 `data`(虽然语义上不应出现,但类型允许) 4. `message` 为空字符串 - **规范依据**:编码规范十、测试规范「工具函数覆盖率目标 100%」 #### BUG-T02:测试描述缺少行为意图 - **位置**:`src/shared/types/action-state.test.ts:4` - **问题**:`describe("ActionState")` 过于宽泛,未说明被测行为 - **规范依据**:编码规范 10.2「描述应说明预期行为」 - **改进建议**:`describe("ActionState 类型构造")` --- ### 2.4 跨文件违规(使用方导入问题) #### BUG-X01:`exams/actions.ts` 类型导入违规 - **位置**:`src/modules/exams/actions.ts:4` - **问题**:`import { ActionState } from "@/shared/types/action-state"` — `ActionState` 仅作为类型使用,应使用 `import type` - **规范依据**:编码规范 4.2.6「所有仅用于类型的导入必须使用 `import type`」 - **改进建议**:`import type { ActionState } from "@/shared/types/action-state"` #### BUG-X02:`questions/actions.ts` 类型导入违规 - **位置**:`src/modules/questions/actions.ts:7` - **问题**:同 BUG-X01,`import { ActionState }` 应为 `import type { ActionState }` - **改进建议**:`import type { ActionState } from "@/shared/types/action-state"` --- ### 2.5 tsconfig.json 配置不达标(影响类型安全) #### BUG-C01:`target` 低于规范要求 - **位置**:`tsconfig.json:3` - **问题**:`"target": "ES2017"`,编码规范 4.1 要求 `"ES2022"` - **影响**:无法使用 ES2022 特性(如 `Array.at()`、`Object.hasOwn()`) - **改进建议**:`"target": "ES2022"` #### BUG-C02:缺少 `noUncheckedIndexedAccess` - **位置**:`tsconfig.json` - **问题**:未启用 `noUncheckedIndexedAccess`,数组/对象索引访问返回 `T` 而非 `T | undefined` - **影响**:`permissions.ts:198` 中 `ROLE_PERMISSIONS[name]` 在 `name` 不存在时返回 `Permission[]` 而非 `Permission[] | undefined`,存在运行时风险 - **规范依据**:编码规范 4.1 - **改进建议**:`"noUncheckedIndexedAccess": true` #### BUG-C03:缺少 `noImplicitReturns` 和 `noFallthroughCasesInSwitch` - **位置**:`tsconfig.json` - **问题**:未启用这两个严格检查 - **规范依据**:编码规范 4.1 - **改进建议**:补充 `"noImplicitReturns": true`、`"noFallthroughCasesInSwitch": true`、`"forceConsistentCasingInFileNames": true` --- ## 三、React 性能优化(应用 `vercel-react-best-practices` 技能) ### PERF-01:`use-permission.ts` 回调函数未 memoize - **位置**:`src/shared/hooks/use-permission.ts:11-25` - **问题**:`hasPermission`、`hasAnyPermission`、`hasAllPermissions`、`hasRole` 每次渲染都创建新函数引用,导致依赖这些函数的子组件不必要重渲染 - **违反规则**:`rerender-functional-setstate`、`rerender-memo` - **改进建议**:使用 `useCallback` 包裹所有回调函数 ### PERF-02:`permissions` 和 `roles` 数组未 memoize - **位置**:`src/shared/hooks/use-permission.ts:8-9` - **问题**:每次渲染都执行 `?? []` 创建新数组引用,导致下游 `useEffect`/`useMemo` 依赖项失效 - **违反规则**:`rerender-derived-state`、`rerender-dependencies` - **改进建议**:使用 `useMemo` 包裹数组派生 ### PERF-03:`as` 断言使用 - **位置**:`src/shared/hooks/use-permission.ts:8-9` - **问题**:`as Permission[]` 和 `as string[]` 使用了类型断言,违反编码规范 4.2.3 - **改进建议**:依赖 `next-auth.d.ts` 的类型增强(已存在),移除断言;或增加类型守卫 ### `use-permission.ts` 完整改进示例 ```typescript import { useCallback, useMemo } from "react" import { useSession } from "next-auth/react" import type { Permission } from "@/shared/types/permissions" export function usePermission() { const { data: session } = useSession() const permissions = useMemo( () => (session?.user?.permissions ?? []) as Permission[], [session?.user?.permissions] ) const roles = useMemo( () => (session?.user?.roles ?? []) as string[], [session?.user?.roles] ) const hasPermission = useCallback( (permission: Permission): boolean => permissions.includes(permission), [permissions] ) const hasAnyPermission = useCallback( (...perms: Permission[]): boolean => perms.some((p) => permissions.includes(p)), [permissions] ) const hasAllPermissions = useCallback( (...perms: Permission[]): boolean => perms.every((p) => permissions.includes(p)), [permissions] ) const hasRole = useCallback( (role: string): boolean => roles.includes(role), [roles] ) return { permissions, roles, hasPermission, hasAnyPermission, hasAllPermissions, hasRole } } ``` --- ## 四、Web 界面规范审查(应用 `web-design-guidelines` 技能) > 说明:`src/shared/types/` 为纯类型定义文件,无直接 UI 代码。以下审查针对类型定义所支撑的 UI 实现层(`use-permission.ts`、`proxy.ts`、`auth-guard.ts`)是否符合 Web Interface Guidelines。 ### UI-01:权限状态可能导致 hydration mismatch - **位置**:`src/shared/hooks/use-permission.ts:7` - **问题**:`useSession()` 在服务端渲染时返回 `null`/`loading`,客户端首次渲染后才有权限数据,导致权限相关的 UI(如菜单项、按钮)在 hydration 后闪烁 - **违反规则**:Web Interface Guidelines — Hydration Safety - **改进建议**: 1. 服务端组件应通过 `auth()` 获取权限并作为 props 传递 2. 客户端组件在 `session === null` 时渲染骨架屏或占位,避免权限相关 UI 闪烁 3. 对权限相关的动态 UI 使用 `suppressHydrationWarning` 或延迟渲染 ### UI-02:权限不足时的重定向未反映在 URL - **位置**:`src/proxy.ts:75-76` - **问题**:权限不足时直接重定向到默认页,URL 中未携带原始路径信息,用户无法知道「为何被重定向」 - **违反规则**:Web Interface Guidelines — Navigation & State「URL reflects state」 - **改进建议**:重定向时携带 `?from=originalPath&reason=forbidden` 参数,目标页显示提示 ### UI-03:错误消息缺少修复步骤 - **位置**:`src/shared/lib/auth-guard.ts:13` - **问题**:`Permission denied: ${permission}` 仅描述问题,未提供下一步操作 - **违反规则**:Web Interface Guidelines — Content & Copy「Error messages include fix/next step」 - **改进建议**:`权限不足:需要 ${permission} 权限。请联系管理员授权或切换账号。` --- ## 五、架构文档同步问题 ### DOC-01:004 文件行数记录过期 - **位置**:`docs/architecture/004_architecture_impact_map.md:408` - **问题**:记录 `types/permissions.ts | 92 | 54 个权限点常量`,实际文件 114 行,含 `DataScope`、`AuthContext` 类型定义 - **改进建议**:更新为 `114 行 | 54 个权限点 + DataScope + AuthContext` ### DOC-02:005 JSON 中 `DataScope` 定义字段顺序与代码不一致 - **位置**:`docs/architecture/005_architecture_data.json:993` - **问题**:JSON 中字段顺序为 `all, owned, class_taught, grade_managed, class_members, children`,代码中为 `all, owned, class_members, grade_managed, class_taught, children` - **改进建议**:同步 JSON 字段顺序与源码一致 ### DOC-03:缺少 `Role` 类型定义记录 - **问题**:若按 BUG-P03 建议新增 `Role` 类型,需在 005 JSON 的 `shared.types` 数组中补充记录 - **改进建议**:新增 `Role` 类型节点,记录 `usedBy: ["auth-guard", "permissions", "proxy"]` --- ## 六、问题汇总统计 | 严重度 | 数量 | 问题编号 | |--------|------|----------| | 高 | 8 | BUG-A01, BUG-A02, BUG-P01, BUG-P02, BUG-P03, BUG-P04, BUG-P05, BUG-P06 | | 中 | 6 | BUG-T01, BUG-T02, BUG-X01, BUG-X02, BUG-C01, BUG-C02 | | 低 | 3 | BUG-C03, DOC-01, DOC-02, DOC-03 | | 性能 | 3 | PERF-01, PERF-02, PERF-03 | | 界面 | 3 | UI-01, UI-02, UI-03 | | **合计** | **23** | | --- ## 七、修复优先级建议 ### P0(立即修复 — 影响类型安全与一致性) 1. BUG-A01:移除 `action-state.ts` 分号 2. BUG-X01、BUG-X02:修正 `import type` 违规 3. BUG-C01、BUG-C02、BUG-C03:升级 `tsconfig.json` ### P1(本迭代修复 — 影响可维护性) 4. BUG-P01:统一权限点命名 5. BUG-P02:`Permissions` 添加 `satisfies` 6. BUG-P03:新增 `Role` 类型 7. BUG-A02、BUG-P04、BUG-P05:补充 JSDoc 8. PERF-01、PERF-02、PERF-03:`use-permission.ts` 性能优化 ### P2(下迭代修复 — 增强健壮性) 9. BUG-T01、BUG-T02:补充测试用例 10. BUG-P06:`DataScope.class_members` 携带 classIds 11. UI-01、UI-02、UI-03:界面规范改进 ### P3(文档同步) 12. DOC-01、DOC-02、DOC-03:同步架构文档 --- ## 八、验证命令 修复完成后应运行以下命令确保零错误: ```bash npm run lint npx tsc --noEmit npm run test:unit -- action-state ``` --- > 报告生成人:AI Agent(GLM-5.2) > 核查方法:人工逐行审查 + 架构图比对 + 技能规则匹配