
Metabase Embedding SDK 的ActionResultForKind类型详解按 ActionKind 驱动的可判别结果类型【免费下载链接】metabaseThe easy-to-use open source Business Intelligence and Embedded Analytics tool that lets everyone work with data :bar_chart:项目地址: https://gitcode.com/GitHub_Trending/me/metabaseActionResultForKind是 Metabase Embedding SDKmodular embedding SDK中用于把ActionKind字面量映射为对应 action 响应体的 TypeScript 条件类型它是useActionhook 实现类型安全地读取 action 执行结果这一能力的关键。本篇文章以 ActionResultForKind.md 为骨架结合 SDK 官方文档 actions.md 与配套 API 片段完整讲解该类型的定义、五种 kind 对应的结果形状、useAction的泛型用法、以及省略TKind时的联合类型收窄策略帮助你在嵌入式应用中写出零as强转的 action 调用代码。一、类型定义一个条件类型五个结果形状ActionResultForKind的完整定义如下节选自 ActionResultForKind.mdtype ActionResultForKindTKind TKind extends create ? ActionResultForCreate : TKind extends update ? ActionResultForUpdate : TKind extends delete ? ActionResultForDelete : TKind extends bulk ? ActionResultForBulk : TKind extends sql ? ActionResultForSql : AnyActionResult;其设计意图在文档中写得很直白将ActionKind字面量映射为对应的可判别discriminatedresult形状。省略TKind即传入undefined时则回退到AnyActionResult联合类型。1.1 类型参数Type Parameters类型参数约束TKindextendsActionKind|undefinedActionKind本身是一个五值字面量联合类型见 ActionKind.mdtype ActionKind create | update | delete | bulk | sql;它对外暴露的是一个扁平的、只有五个值的公共 kind 集合但在后端它映射到了命名空间化的row/*、bulk/*的implicitKind以及query类型的type值。也就是说create/update/delete始终指单行操作bulk覆盖任何批量变体批量创建 / 更新 / 删除sql覆盖自定义 SQL action对应后端的query类型 action。SDK 把这套后端繁杂的命名空间收敛成五值表面方便调用方记忆和使用。二、五种结果形状每个 kind 对应什么响应体ActionResultForKind的每个分支都对应一个具体的类型下面逐一展开来源ActionResultForCreate.md、ActionResultForUpdate.md、ActionResultForDelete.md、ActionResultForBulk.md、ActionResultForSql.md。2.1create→ActionResultForCreatetype ActionResultForCreate { created-row: Recordstring, RowValue; };单行插入basic action的响应返回被插入的那一行以Recordstring, RowValue形式呈现key 为列名。其中RowValue定义为type RowValue string | number | null | boolean | object;即查询结果或 action 响应中的单个值可以是字符串、数字、null、布尔值或对象。2.2update→ActionResultForUpdatetype ActionResultForUpdate { rows-updated: readonly RowValue[]; };单行更新操作返回受影响的主键集合类型为只读数组readonly RowValue[]。2.3delete→ActionResultForDeletetype ActionResultForDelete { rows-deleted: readonly RowValue[]; };单行删除操作同样返回受影响的主键集合类型为readonly RowValue[]。可以看到 update 与 delete 的形状结构高度一致只是 key 不同rows-updatedvsrows-deleted这正是判别联合可以区分的依据。2.4bulk→ActionResultForBulktype ActionResultForBulk { rows-created?: number; rows-deleted?: number; rows-updated?: number; success: boolean; };任意批量变体的响应——一个success布尔标志外加三个可选的计数rows-created?、rows-deleted?、rows-updated?。注意这三个计数都是可选属性具体出现哪些取决于批量操作实际执行的类型。2.5sql→ActionResultForSqltype ActionResultForSql { rows-affected: number; };自定义 SQL action 的响应只返回一个rows-affected数字表示受影响的记录数。2.6 汇总对照表Action kind覆盖范围result形状create单行插入basic action{ created-row: Recordstring, RowValue }update单行更新{ rows-updated: readonly RowValue[] }delete单行删除{ rows-deleted: readonly RowValue[] }bulk任意批量变体批量增删改{ success: boolean; rows-created?: number; rows-updated?: number; rows-deleted?: number }sql自定义 SQL action{ rows-affected: number }三、回退分支AnyActionResult与 TS 收窄当TKind没有提供即undefined时ActionResultForKind落到最后一个分支AnyActionResult。该类型是五种结果形状的并集见 AnyActionResult.mdtype AnyActionResult | ActionResultForCreate | ActionResultForUpdate | ActionResultForDelete | ActionResultForBulk | ActionResultForSql;官方文档解释得很清楚它被用作省略TKind时result的默认类型。对于调用时并不知道 action 的 kind 是什么的开发者得到的依然是一个TypeScript 可收窄narrowable的联合类型而不是一个什么都能装、同时也会吞掉拼写错误读操作的Recordstring, unknown。换句话说联合类型默认值能在编译期拦截错误的 key 访问——如果类型系统无法证明result上存在某个 key它就会直接报错。这比用Recordstring, unknown之后靠运行时undefined兜底要安全得多。四、实战在useAction中使用ActionResultForKindActionResultForKind是useActionhook 返回值类型的一部分。根据 useAction.md 与 UseActionResult.mdhook 签名为function useActionTParameters, TKind( actionId: SdkActionId | null, ): UseActionResultTParameters, TKind;其中返回类型UseActionResult的result与execute字段都引用了ActionResultForKindresult:ActionResultForKindTKind | null—— 最近一次响应体首次调用前与reset()之后为null。execute(parameters): 返回PromiseActionResultForKindTKind | null—— 成功时解析为对应 kind 的判别结果形状省略TKind时解析为AnyActionResult可用key in r收窄当actionId为null或 SDK 尚未初始化时解析为null且不发请求。4.1 已知 kind直接获得精确类型当你知道 action 的 kind 时把它作为第二个泛型传入result就会被自动推断为对应的单一形状无需任何类型断言。官方示例 typed-response.tsx 中演示了用sqlkind 调用一个设置订单折扣的自定义 SQL actionimport { MetabaseProvider, defineMetabaseAuthConfig, useAction, } from metabase/embedding-sdk-react; const authConfig defineMetabaseAuthConfig({ metabaseInstanceUrl: https://your-metabase.example.com, }); const SET_DISCOUNT_ACTION_ID 42; type SetDiscountParameters { id: number; discount: number }; function SetDiscountButton({ orderId }: { orderId: number }) { const { execute, result } useActionSetDiscountParameters, sql( SET_DISCOUNT_ACTION_ID, ); const onClick async () { await execute({ id: orderId, discount: 0.1 }); }; // result 的类型是 { rows-affected: number } | null —— 无需强转 const affected result?.[rows-affected]; return ( button onClick{onClick} Apply 10% discount{affected ! null ? (${affected} rows) : } /button ); }几点实战要点actionId传的是 action 的数字 id、entity_id字符串或null。数字 id 可以在 Metabase 中打开 action 编辑器从 URL 里复制。TParameters描述传给execute的参数对象其 key 必须是 action 参数的slug即 action 编辑器中显示的名称而不是显示名name。例如参数显示名是Discountslug 是discount则传参 key 必须写discount。参数值支持字符串、数字、布尔值日期传 ISO 8601 字符串。hook不会在挂载时自动执行必须在事件处理器里显式调用execute。需要条件性拦截时在事件处理器里分支判断如if (!user.canEdit) return;后再调用。4.2 未知 kind用in操作符收窄联合如果你事先不知道 action 的 kind省略第二个泛型result会变成AnyActionResult | null。此时用in操作符即可在运行时完成判别收窄TS 会在每个分支内给出精确类型。同一个示例文件里演示了这种做法const { execute, result } useActionSetDiscountParameters( SET_DISCOUNT_ACTION_ID, ); const onClick async () { await execute({ id: orderId, discount: 0.1 }); }; let summary Apply discount; if (result rows-affected in result) { // 这里 result[rows-affected] 的类型是 number summary ${result[rows-affected]} rows affected; } else if (result created-row in result) { // 这里 result[created-row] 的类型是 Recordstring, RowValue summary Row created; }这种写法的核心价值在于created-row、rows-updated、rows-deleted、rows-affected这些 key 在不同结果形状间互不重叠天然构成判别属性因此in收窄在编译期就是可靠的。而bulk形状里的success是布尔标志计数属性全部可选也可以作为补充判别维度使用。五、读写结果时的工程建议5.1 成功后记得刷新数据useAction不会在 action 成功后自动刷新任何数据。如果页面上有 action 可能改动的数据必须手动让它重新查询否则屏幕上的数据可能是过期的。官方推荐用重新挂载的方式维护一个refreshKey状态把它作为 question 组件的keyaction 成功执行后递增该 key新的 key 会让 question 重新挂载并重跑查询。如果单个 action 会影响多个视图就让所有依赖的 question 共享同一个refreshKey一次状态变更即可让它们一起重新查询。不要试图用result直接驱动界面数据。响应体是用来确认的行数、被插入行的主键等你可以用它来显示 toast 或做详情页导航但屏幕上的数据仍然需要重新读取数据源。5.2 错误处理与响应体配合如果读取结果不是必须的完全可以不读。但一旦读取请遵循上面的规则知道 kind 就传TKind不知道就用in收窄。error字段被规范化为ActionExecuteError | nullerror.status是可选属性HTTP 层失败4xx/5xx时存在传输层失败离线、请求被中止时不存在。error.data.message是给终端用户看的可操作诊断信息。error.data.errors是后端报告参数级校验失败时的按字段映射{ slug: message }key 与传给execute的参数 slug 一致整请求失败如外键约束时为空{}信息在error.data.message。SQL 或驱动错误的消息常常带换行后面跟着失败的 SQL 语句因此渲染错误信息时建议使用white-space: pre-wrap的容器如pre而不是span会把换行压成一段文字。错误消息应原样展示不要替换成Something went wrong这类笼统文案。六、总结ActionResultForKind是 Metabase Embedding SDK 类型体系里精巧的一环它用一层条件类型把后端的 action kind 命名空间收敛成五个公共字面量并把每个字面量绑定到精确的响应体形状。配合useAction的第二个泛型参数你可以获得零强转的类型安全体验省略该参数时联合类型默认值依然保留in收窄能力防止把类型错误吞成运行时undefined。理解这张类型映射表是写出健壮、可维护的嵌入式 action 调用代码的第一步。延伸阅读useAction hook 完整指南action 触发、参数 slug、日期与时区、错误处理与刷新策略的完整说明ActionKind、AnyActionResult、RowValue 等配套类型定义UseActionResulthook 返回值的完整属性表ActionExecuteError错误对象结构【免费下载链接】metabaseThe easy-to-use open source Business Intelligence and Embedded Analytics tool that lets everyone work with data :bar_chart:项目地址: https://gitcode.com/GitHub_Trending/me/metabase创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考