diff --git a/lib/types/Exception.d.ts b/lib/types/Exception.d.ts index d85ed77..409e333 100644 --- a/lib/types/Exception.d.ts +++ b/lib/types/Exception.d.ts @@ -2,7 +2,21 @@ import { StorageSchema } from "."; import { EntityDict, OpRecord } from "./Entity"; import { EntityDict as BaseEntityDict } from '../base-app-domain'; declare const OAK_EXCEPTION_SYMBOL: unique symbol; -export declare function isOakException(obj: any): obj is OakException; +/** + * 判断一个对象是否为 OakException 实例,作用和 `instanceof` 类似,但更安全可靠。 + * 如OakUserException继承自OakException,使用时可传入OakUserException以进一步确认类型。 + * @param obj 需要判断的对象 + * @param exceptionName 可选参数,指定异常类名以进一步确认 + * + * ```ts + * if (isOakException(e, OakUserException)) { + * // 这里的 e 已被类型缩小为 OakUserException + * } + * ``` + * + * @returns 如果对象是 OakException 实例则返回 true,否则返回 false + */ +export declare function isOakException>(obj: any, errType?: new () => T): obj is T; export declare class OakException extends Error { opRecords: OpRecord[]; _module?: string; diff --git a/lib/types/Exception.js b/lib/types/Exception.js index 599f476..0b3427e 100644 --- a/lib/types/Exception.js +++ b/lib/types/Exception.js @@ -6,8 +6,53 @@ exports.makeException = makeException; const relation_1 = require("../store/relation"); const lodash_1 = require("../utils/lodash"); const OAK_EXCEPTION_SYMBOL = Symbol.for('oak-domain:exception'); -function isOakException(obj) { - return obj && obj[OAK_EXCEPTION_SYMBOL] === true; +/** + * 判断一个对象是否为 OakException 实例,作用和 `instanceof` 类似,但更安全可靠。 + * 如OakUserException继承自OakException,使用时可传入OakUserException以进一步确认类型。 + * @param obj 需要判断的对象 + * @param exceptionName 可选参数,指定异常类名以进一步确认 + * + * ```ts + * if (isOakException(e, OakUserException)) { + * // 这里的 e 已被类型缩小为 OakUserException + * } + * ``` + * + * @returns 如果对象是 OakException 实例则返回 true,否则返回 false + */ +function isOakException(obj, errType) { + if (!obj) { + return false; + } + const isOakException = !!obj[OAK_EXCEPTION_SYMBOL]; + if (isOakException) { + if (!errType) { + return true; + } + } + else { + return false; + } + try { + let proto = Object.getPrototypeOf(obj); + const expectedName = errType.name; + let depth = 0; + const maxDepth = 10; // 防止无限循环 + while (proto && depth < maxDepth) { + const constructorName = proto.constructor?.name; + if (constructorName === expectedName) { + return true; + } + proto = Object.getPrototypeOf(proto); + depth++; + } + return false; + } + catch (e) { + console.warn(e); + // 如果检查过程出错,安全返回 false + return false; + } } class OakException extends Error { opRecords; diff --git a/src/types/Exception.ts b/src/types/Exception.ts index 895744e..965886a 100644 --- a/src/types/Exception.ts +++ b/src/types/Exception.ts @@ -7,8 +7,55 @@ import { pick } from '../utils/lodash'; const OAK_EXCEPTION_SYMBOL = Symbol.for('oak-domain:exception'); -export function isOakException(obj: any): obj is OakException { - return obj && obj[OAK_EXCEPTION_SYMBOL] === true; +/** + * 判断一个对象是否为 OakException 实例,作用和 `instanceof` 类似,但更安全可靠。 + * 如OakUserException继承自OakException,使用时可传入OakUserException以进一步确认类型。 + * @param obj 需要判断的对象 + * @param exceptionName 可选参数,指定异常类名以进一步确认 + * + * ```ts + * if (isOakException(e, OakUserException)) { + * // 这里的 e 已被类型缩小为 OakUserException + * } + * ``` + * + * @returns 如果对象是 OakException 实例则返回 true,否则返回 false + */ +export function isOakException>(obj: any, errType?: new () => T): obj is T { + if (!obj) { + return false; + } + + const isOakException = !!obj[OAK_EXCEPTION_SYMBOL]; + if (isOakException) { + if (!errType) { + return true; + } + } else { + return false; + } + + try { + let proto = Object.getPrototypeOf(obj); + const expectedName = errType.name; + let depth = 0; + const maxDepth = 10; // 防止无限循环 + + while (proto && depth < maxDepth) { + const constructorName = proto.constructor?.name; + if (constructorName === expectedName) { + return true; + } + proto = Object.getPrototypeOf(proto); + depth++; + } + + return false; + } catch (e) { + console.warn(e); + // 如果检查过程出错,安全返回 false + return false; + } } export class OakException extends Error {