export const enforceCatchType = { meta: { type: "problem", docs: { description: "强制 catch 子句使用 e: unknown,并用 instanceof Error 提取错误信息;空的 catch 块应添加注释说明原因", }, messages: { missingTypeAnnotation: "catch 子句缺少类型注解。请使用 catch (e: unknown),然后用 e instanceof Error ? e.message : String(e) 提取错误信息。", nonUnknownType: "catch 的类型注解应为 unknown,切勿使用 any。请改为 catch (e: unknown),然后用 e instanceof Error ? e.message : String(e) 提取错误信息。", emptyCatchNoComment: "空的 catch 块应添加注释说明为什么忽略此异常。如果确有理由静默吞掉错误,请在该 catch body 内添加注释。", }, schema: [], }, create(context) { const sourceCode = context.sourceCode ?? context.getSourceCode(); function isUnknownType(typeAnnotation) { if (!typeAnnotation) return false; const type = typeAnnotation.typeAnnotation; if (type?.type === "TSTypeReference") { return type.typeName?.name === "unknown"; } return false; } function hasCommentsInBody(body) { if (!body) return false; return sourceCode.getCommentsInside(body).length > 0; } function check(node) { const { param, body } = node; if (param) { const typeAnnotation = param.typeAnnotation; if (!typeAnnotation) { context.report({ node: param, messageId: "missingTypeAnnotation" }); } else if (!isUnknownType(typeAnnotation)) { context.report({ node: typeAnnotation, messageId: "nonUnknownType" }); } } if ( body && body.type === "BlockStatement" && body.body.length === 0 && !hasCommentsInBody(body) ) { context.report({ node: body, messageId: "emptyCatchNoComment" }); } } return { CatchClause: check, }; }, };