
fuels-ts 错误处理核心包实战深入 fuel-ts/errors 的 FuelError 类、ErrorCode 错误码体系与断言工具【免费下载链接】fuels-tsFuel Network Typescript SDK项目地址: https://gitcode.com/GitHub_Trending/fu/fuels-tsfuel-ts/errors即fuel-ts/errors是 Fuel Network TypeScript SDKfuels-ts官方 monorepo 中专门负责内部错误抛出的核心工具的子包它统一定义了整个 SDK 抛错所用的错误类与错误码。读完本文你将掌握在 fuels-ts 内部模块与外部应用中创建、解析、序列化 FuelError 的完整姿势理解 ErrorCode 的分类体系并学会用expectToThrowFuelError、safeExec等测试工具编写健壮的错误断言测试。全文以 packages/errors/README.md 为骨架结合该包源码与测试用例逐层展开。一、fuel-ts/errors 在 fuels-ts 中的定位fuel-ts/errors是 fuels-ts 生态中众多子包之一。从 packages/errors/package.json 可以看到它的官方描述是Error class and error codes that the fuels-ts library throws即「fuels-ts 库抛出错误所使用的错误类与错误码」。这意味着它的角色不是某个业务功能模块而是贯穿 SDK 各包account、abi-typegen、utils、fuelsCLI 等的错误基础设施。几个可以从仓库确认的关键事实当前仓库内该包版本为0.103.0对外通过dist/index.js、dist/index.mjs、dist/index.d.ts提供 CommonJS / ESM / 类型三种入口同时额外暴露./test-utils子路径导出见 package.json运行时只依赖fuel-ts/versionsworkspace:*用于在错误对象上附带各相关依赖的版本信息便于诊断其导出被伞形包fuels统一收口在 packages/fuels/src/index.ts 中有export * from fuel-ts/errors在 packages/fuels/src/test-utils.ts 中有export * from fuel-ts/errors/test-utils。也就是说用户从fuels或fuels/test-utils导入也同样可用。从源码结构看该包只包含两个核心业务文件与一组测试工具error-codes.ts错误码枚举、fuel-error.ts错误类实现、test-utils/safeExec与expectToThrowFuelError。二、安装与引入fuel-ts/errors可以独立安装也可以直接通过伞形包fuels间接使用pnpm add fuel-ts/errors # 或 npm add fuel-ts/errors安装后即可在代码中导入核心类型import { FuelError, ErrorCode } from fuel-ts/errors;FuelErrorSDK 统一使用的错误类继承自原生ErrorErrorCode错误码枚举每个枚举成员对应一个稳定的字符串值。如需使用测试工具则需要从子路径导入注意普通运行时依赖不含测试工具import { expectToThrowFuelError } from fuel-ts/errors/test-utils;三、核心类 FuelError 与错误码 ErrorCode 的实现原理fuel-ts/errors的全部源码逻辑集中在 fuel-error.ts 与 error-codes.ts 两个文件中公开入口见 index.tsexport { ErrorCode } from ./error-codes; export { FuelError } from ./fuel-error;3.1 ErrorCode字符串化的错误码枚举FuelError 采用「字符串错误码」而非数字错误码因为字符串码跨语言、跨进程、跨前后端传输时语义稳定、可读性高。以 error-codes.ts 中的定义为例export enum ErrorCode { // abi NO_ABIS_FOUND no-abis-found, INVALID_DATA invalid-data, // provider INVALID_PROVIDER invalid-provider, // wallet WALLET_MANAGER_ERROR wallet-manager-error, // transaction INSUFFICIENT_FUNDS not-enough-funds, // unknown UNKNOWN unknown, }注意一个反直觉的细节部分枚举成员名与其字符串值并不相同例如INSUFFICIENT_FUNDS_OR_MAX_COINS的值为not-enough-funds-or-max-coins-reachedINSUFFICIENT_FUNDS的值为not-enough-fundsCONVERTING_FAILED的值为converting-error。所以当你在代码里用error.code与字符串比较或在日志、数据库、远端诊断中心比对错误码时务必以字符串值为准而不是枚举成员名。3.2 FuelError携带元数据的统一错误类从 fuel-error.ts 的源码可以看到它的核心设计export class FuelError extends Error { static readonly CODES ErrorCode; readonly VERSIONS versions; readonly metadata: Recordstring, unknown; readonly rawError: unknown; static parse(e: unknown) { /* ... */ } code: ErrorCode; constructor( code: ErrorCode, message: string, metadata: Recordstring, unknown {}, rawError: unknown null ) { super(message); this.code code; this.name FuelError; this.metadata metadata; this.rawError rawError; } toObject() { const { code, name, message, metadata, VERSIONS, rawError } this; return { code, name, message, metadata, VERSIONS, rawError }; } }构造函数的关键点参数类型默认值作用codeErrorCode必填机器可读的错误码用于程序化分支与诊断messagestring必填人类可读的错误描述会被传给原生ErrormetadataRecordstring, unknown{}附加的结构化上下文如出错参数、地址、交易哈希等rawErrorunknownnull保留的底层原始错误如下游 SDK / RPC 返回的原生异常此外还提供三个重要成员FuelError.CODESErrorCode的静态别名因此既可以写FuelError.CODES.INVALID_DATA也可以写ErrorCodes.INVALID_DATA注意README 中两种写法fuel-ts/error与ErrorCodes均为示例笔误实际导出名称是fuel-ts/errors与ErrorCodeVERSIONS实例字段值为fuel-ts/versions提供的版本信息快照方便在排查线上问题时确认用户用的各依赖版本toObject()将错误转换为纯对象code/name/message/metadata/VERSIONS/rawError便于日志序列化或跨进程传输。在 fuel-error.test.ts 中构造函数行为有直接验证创建实例后message、code、name、VERSIONS会被分别断言为传入值、ErrorCode.PARSE_FAILED、FuelError与versions快照。四、ErrorCode 枚举全貌按领域分类错误码并非一盘散沙而是按 fuels-ts 的功能域在 error-codes.ts 中分区注释组织大致包括以下类别每类摘取若干代表完整定义请直接查看该文件领域代表错误码字符串值ABI / 编解码no-abis-found、abi-types-and-values-mismatch、invalid-decode-value、unsupported-encoding-version地址invalid-address、invalid-evm-address、invalid-b256-addressProvider / 网络missing-provider、invalid-provider、connection-refused、invalid-url、unsupported-feature钱包 / 账户invalid-public-key、wallet-manager-error、missing-connector、invalid-password、account-required通用错误parse-failed、encode-error、decode-error、not-implemented、not-supported、element-not-found资金 / 交易not-enough-funds、not-enough-funds-or-max-coins-reached、gas-price-too-low、transaction-not-found、transaction-squeezed-out、max-inputs-exceeded收据 / 脚本invalid-receipt-type、script-reverted、script-return-invalid-type助记词 / 加密invalid-mnemonic、invalid-entropy、invalid-credentials其他invalid-ttl、number-too-big、stream-parsing-error、node-launch-failed、unknown其中HASHER_LOCKED已被标记为deprecated不再使用UNKNOWN作为兜底码存在。这样一个集中式枚举的价值在于上层代码如 fuels CLI 的 createWallet.ts、loadConfig.ts只需import { FuelError } from fuel-ts/errors即可与全 SDK 共用同一套错误语言。五、SDK 内部使用如何抛出一个规范错误对 SDK 内部模块而言规范做法是「永远不要直接throw new Error(...)而是统一抛出FuelError」并使用预定义的错误码。README 给出的两种等价写法如下import { FuelError, ErrorCode } from fuel-ts/errors; export function singleImport() { // 通过 FuelError.CODES 静态别名访问错误码 throw new FuelError(FuelError.CODES.INVALID_DATA, Invalid data); } export function multipleImports() { // 通过 ErrorCode 枚举直接访问错误码 throw new FuelError(ErrorCode.INVALID_DATA, Invalid data); }两种方式完全等价——因为源码中static readonly CODES ErrorCode它们指向同一个枚举对象。推荐携带更多上下文例如throw new FuelError( ErrorCode.INSUFFICIENT_FUNDS, Balance is lower than the required amount for this transaction., { assetId, required: amount.toString() }, // metadata 附带结构化上下文 originalError // rawError 保留底层异常 );这样抛出的错误自带稳定的code为后续的「程序化分支」「日志检索」「用户友好提示映射」打下基础。六、外部使用跨进程解析与国际化错误发生在内部但真正被消费的地方往往在应用层——例如钱包 DApp、dApp 前端或后端服务。FuelError提供了静态方法parse(e: unknown)可以把「从任意边界RPC、iframe、postMessage、JSON 反序列化等拿到的未知对象」重新还原成规范的FuelError。6.1 parse 的守卫逻辑从 fuel-error.ts 可以看到parse的校验步骤若传入对象没有code属性抛出ErrorCode.PARSE_FAILED消息为Failed to parse the error object. The required code property is missing.若code不在ErrorCode枚举值集合内用Object.values(ErrorCode)比对抛出ErrorCode.PARSE_FAILED并在消息中列出所有可接受的错误码通过校验后构造并返回新的FuelError(error.code, error.message, error.metadata, error.rawError)。以上三条路径在 fuel-error.test.ts 中均有测试覆盖包括正常解析parse({ code: ErrorCode.INVALID_DATA, message })、缺失code时抛错、未知 code 时抛错并给出可用错误码清单。6.2 基于 code 做错误文案映射i18n正是由于每个错误都携带稳定字符串码应用层可以做「错误码 → 本地化文案」映射。README 给出的外部使用示例思路如下下文代码已修正为可运行的写法import { FuelError, Provider } from fuels; type Locale pt-BR | bs-BA | en-GB; const currentLocale: Locale pt-BR; const i18nDict { pt-BR: { [FuelError.CODES.INVALID_DATA]: Dados inválidos }, bs-BA: { [FuelError.CODES.INVALID_DATA]: Nevažeći podaci }, en-GB: { [FuelError.CODES.INVALID_DATA]: Invalid data }, }; function translateError(e: unknown) { // 1. 把任何来源的未知错误对象解析为 FuelError const { code } FuelError.parse(e); // 2. 用 code 查表得到当前语言环境下的文案 return i18nDict[currentLocale][code]; } try { const p new Provider(http://localhost:4000); console.log(p); } catch (e) { const prettyError translateError(e); console.log({ prettyError }); }这段代码演示的完整闭环是Provider构造失败 → SDK 内部抛出带code的FuelError→ 应用层用FuelError.parse安全还原 → 依据code映射为用户可读的本地化文案。生产环境中还可以把code当作埋点事件的维度、把metadata输出到日志平台做聚合分析。七、跨进程传输toObject 与 VERSIONS由于FuelError是类实例直接跨进程 / 跨 iframe 传输会丢失原型与方法。仓库为此提供了两条互补路径序列化调用error.toObject()得到纯 JSON 对象{ code, name, message, metadata, VERSIONS, rawError }可直接JSON.stringify反序列化对端收到后调用FuelError.parse(obj)重新包装回FuelError实例。对应的往返验证在 fuel-error.test.ts构造带metadata的错误后断言toObject()输出与{ code, name, message, VERSIONS: err.VERSIONS, metadata, rawError: null }完全一致。附带版本信息这一设计非常实用——fuel-error.ts 中的VERSIONS字段直接来自fuel-ts/versions让每个被序列化的错误都能自报「是哪一批依赖版本抛出的」大幅降低远程排查成本。八、测试工具expectToThrowFuelError 与 safeExec错误系统的另一半价值体现在测试侧。README 强调「使用expectToThrowFuelError测试工具来断言错误」它同样可以通过伞形包fuels引入见 packages/fuels/src/test-utils.ts。8.1 safeExec捕获「抛出型」逻辑实现位于 safeExec.tsexport const safeExec async TResult unknown, TError extends Error Error( lambda: () TResult ) { let error: TError | undefined; let result: TResult | undefined; try { result await lambda(); } catch (_error: unknown) { error _error as TError; } return { error, result }; };它接收一个同步或异步的 lambda把它包进try/catch无论成功失败都以{ error, result }二元组返回——成功时result有值、error为undefined失败时反之。这为后续统一断言铺平了道路。8.2 expectToThrowFuelError强校验的断言工具核心逻辑位于 expect-to-throw-fuel-error.ts签名如下type ExpectedFuelError PartialFuelError RequiredPickFuelError, code; export const expectToThrowFuelError async ( lambda: () unknown, expectedError: ExpectedFuelError ) { /* ... */ };它内部通过safeExec执行 lambda然后做逐项强校验任何一项不满足都会让测试失败并附上明确的错误信息expectedError必须携带code否则报Expected error must contain a code.期望的code必须是合法的ErrorCode值与Object.values(ErrorCode)比对lambda 必须真正抛出异常否则报Passed-in lambda didnt throw.实际抛出的错误必须具备code且该code必须是合法ErrorCode值期望码与实际抛出码必须一致否则输出两者供比对若期望对象声明了metadata用expect.objectContaining做部分匹配即只校验声明的键若期望对象声明了message/rawError做严格相等断言最终断言thrownError.name FuelError确保抛出的确实是规范的 FuelError。它在成功断言后会把实际抛出的FuelError作为返回值返回便于继续做补充断言。8.3 在测试中的典型用法先看断言「确实抛出预期的 FuelError」的推荐写法import { expectToThrowFuelError, FuelError, ErrorCode } from fuel-ts/errors; async function myFn() { throw new FuelError(ErrorCode.INVALID_DATA, Invalid data); } describe(this and that, () { it(should throw FuelError, async () { const expected new FuelError(ErrorCode.INVALID_DATA); // 只需给出 codemessage/metadata 等按需补充 await expectToThrowFuelError(() myFn(), expected); }); it(should throw something else, async () { const expected new FuelError(ErrorCode.INVALID_DATA); // 反向场景函数最终抛出的不是目标 FuelError则 expectToThrowFuelError 本身会 reject const fn () expectToThrowFuelError(() myFn(), expected); await expect(fn).rejects.toThrow(Something else); }); });要点归纳期望对象可以只给codeExpectedFuelError规定code为必填其余字段可缺省当被断言函数抛出非预期错误、根本不抛或错误码不匹配时expectToThrowFuelError会以 Promise reject 的方式失败因此可直接放在await上使用若测试目的是「验证抛出的错误不是 FuelError」则把expectToThrowFuelError放进一个函数再用await expect(fn).rejects.toThrow(...)捕获其自身的失败信息。这些边界情况在 expect-to-throw-fuel-error.test.ts 中有完整的对照测试包括「lambda 不抛」「同时支持同步与异步 thrower」「抛出无 code 的错误」「抛出非法 code 的错误」「期望对象缺 code」「期望 code 非法」以及「失败信息包含原始错误内容」例如Thrown error Error: Original Error等七种以上场景。若想在自己的项目里用这套工具可仿照该测试文件组织用例safeExec与expectToThrowFuelError的导出关系可见 test-utils.ts 与 test-utils.test.ts。九、把错误码融入 fuels-ts 实际调用的观察在本仓库中可以观察到错误系统如何在真实模块中落地仅作示例非穷举provider.ts 与 validate-pagination-args.ts 会以ErrorCode.INVALID_INPUT_PARAMETERS等码抛出参数校验错误utils 下的编解码工具如arrayify、base58、dataSlice、toUtf8Bytes在非法输入时抛出带码错误供上层统一捕获fuels CLI 的 createWallet.ts、init/index.ts、forcUtils.ts、loadConfig.ts 等命令实现直接复用fuel-ts/errors保证命令行错误与 SDK 运行时错误使用同一套语义。由此可以推断fuels-ts 的目标是让「SDK 内部错误 → CLI 提示 → 前端展示 → 日志诊断」整条链路共享稳定错误码。如果你要为 fuels-ts 贡献新能力遵循同一模式——从 error-codes.ts 选码或新增码并抛出FuelError——是最省力的做法。同时可参考 CHANGELOG.md 观察错误码随版本演进的历史例如response-body-empty、自动合并 coins 相关码的引入记录以及 package.json 中 Node^20 || ^22 || ^24的引擎约束。小结一句话概括本包的价值fuel-ts/errors把「抛出错误」这件小事工程化——ErrorCode提供全 SDK 统一、跨域分类、字符串化的错误码字典FuelError在原生Error之上附加code / metadata / rawError / VERSIONS并支持parse与toObject的跨进程往返expectToThrowFuelError与safeExec让测试者可以像断言返回值一样断言错误。对于任何基于 fuels-ts 构建的应用接住FuelError.code并做映射处理是让错误处理走向健壮的第一步。【免费下载链接】fuels-tsFuel Network Typescript SDK项目地址: https://gitcode.com/GitHub_Trending/fu/fuels-ts创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考