news 2026/9/13 10:11:32

coze-studio 前端类型包详解:@coze-arch/bot-typings 的类型声明设计与使用

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
coze-studio 前端类型包详解:@coze-arch/bot-typings 的类型声明设计与使用

coze-studio 前端类型包详解:@coze-arch/bot-typings 的类型声明设计与使用

【免费下载链接】coze-studioAn AI agent development platform with all-in-one visual tools, simplifying agent creation, debugging, and deployment like never before. Coze your way to AI Agent creation.项目地址: https://gitcode.com/GitHub_Trending/co/coze-studio

coze-studio 的 Coze bot 前端生态建立在 Rush.js monorepo 之上,多个包之间共享同一套用户、鉴权、路由与平台集成类型。@coze-arch/bot-typings(位于 frontend/packages/arch/bot-typings)就是从 bot 应用中抽取出来的纯 TypeScript 类型定义包:它集中声明了文件模块(图片/样式/SVG)类型、通用工具类型、DataItem用户与鉴权命名空间、以及window/navigator全局扩展,在零运行时依赖的前提下为整个 bot 生态提供类型安全。读完本篇,你可以理解该包各入口的导出结构、每个核心类型的实现细节,以及如何在一个 Rush 工作区项目中正确引用它。

一、包定位与核心特性

根据 README 与 package.json,该包的元信息如下:

  • 包名@coze-arch/bot-typings,版本0.0.1,许可证 Apache-2.0;
  • 描述bot typings that extract from bot/src/typings,即从原 bot 应用的 typings 目录抽取而来;
  • 运行时依赖dependencies为空对象,纯类型声明,无运行时开销。

它提供的能力可分为五类:

  1. 全局模块声明(Global Type Declarations):为图片、样式表、SVG 等文件导入提供类型;
  2. 通用工具类型(Common Utility Types)ObjExpandPartialRequired等类型操纵工具;
  3. 平台相关类型(Platform-Specific Types):浏览器 API、window对象与navigator扩展;
  4. 用户与鉴权类型(User & Authentication Types):用户数据、OAuth 登录流程、验证码等接口的数据结构;
  5. Teamspace 与路由类型:动态路由参数DynamicParams的声明。

1.1 入口导出结构

从 package.json 的exports字段可以看到包对外暴露的三个入口:

{ "exports": { ".": "./src/index.d.ts", "./common": "./src/common.ts", "./teamspace": "./src/teamspace.ts" }, "main": "src/index.d.ts", "types": "src/index.d.ts", "typesVersions": { ".": { "*": ["./src/index.d.ts"] }, "*": { "common": ["./src/common.ts"], "teamspace": ["./src/teamspace.ts"] } } }

这里有两点值得注意:

  • 主入口.指向src/index.d.ts,负责拉入全部全局声明(模块声明 + 全局命名空间扩展);
  • 子路径./common./teamspace直接指向.ts源文件而非.d.ts,并且额外配置了typesVersions映射,保证旧版 TypeScript 或非标准解析路径下也能正确找到类型入口。新增子模块时必须同步更新exports字段(README「Adding New Types」一节也强调了这一点)。

二、快速上手

2.1 在 Rush.js monorepo 中安装

README 给出的安装方式是在宿主包的package.json中声明 workspace 依赖,然后执行rush update

# Add to your package.json "@coze-arch/bot-typings": "workspace:*" # Run Rush update to install rush update

workspace:*是 pnpm 的 workspace 协议,表示始终解析到 monorepo 内的本地版本。coze-studio 仓库的 Rush 配置位于 common/config/rush,子包通过workspace:*相互引用是该仓库的标准做法(本包的devDependencies@coze-arch/bot-env@coze-arch/eslint-config@coze-arch/ts-config均为workspace:*)。

2.2 基本引用方式

// 引入主类型定义(拉入全部全局声明) import "@coze-arch/bot-typings"; // 按需引入子模块 import { BotPageFromEnum, Obj, Expand, PartialRequired } from "@coze-arch/bot-typings/common"; import { DynamicParams } from "@coze-arch/bot-typings/teamspace";

需要说明的是:@coze-arch/bot-typings主入口是副作用式引入(side-effect import),它本身没有值导出,作用是让index.d.ts中的declare module与全局interface扩展进入当前编译上下文。

三、API 参考:结合源码逐一解析

3.1 Common 类型(src/common.ts)

common.ts 只有约 55 行,包含一个枚举和三个工具类型。

BotPageFromEnum:Bot 详情页来源
export enum BotPageFromEnum { Bot = 'bot', //bot list Explore = 'explore', //Explore List Store = 'store', Template = 'template', }

它标识 bot 详情页面是从哪个列表进入的(bot 列表 / 探索列表 / 商店 / 模板)。源码注释写明“currently only bot and explore list”,即实际业务中目前主要使用前两个枚举值,StoreTemplate属于预留扩展。注意它是运行时枚举而非declare enum,因此会真正产出 JS 代码——这是该包中唯一具有运行时产出的导出,也是它必须以.ts文件形式通过exports子路径暴露的原因。

Obj:通用对象类型
export type Obj = Record<string, any>;

后续所有工具类型都以其作为约束基类(如Expand<T extends Obj>)。

Expand<T>:展开交叉类型

README 中的示例解释了用途,而源码给出了具体实现:

/** * Show the full type * * @example * type Intersection = { a: string } & { b: number }; * type Result = Expand<Intersection>; * // Result: { a: string; b: number } */ export type Expand<T extends Obj> = T extends infer U ? { [K in keyof U]: U[K] } : never;

从源码结构看,它用T extends infer U捕获类型参数,再通过一次映射类型(mapped type)把{ a: string } & { b: number }这样的交叉类型“摊平”为对象字面量形态。这样做的好处是:TypeScript 语言服务在悬停提示中会把交叉类型显示为A & B的合并视图,而Expand之后会显示完整、可直接阅读的对象结构,对调试复杂类型非常有用。

PartialRequired<T, K>:指定字段改为必填
/** * Required only for specific fields, often used to correct server level type declaration errors * * @example * interface Agent { * id?: string; * name?: string; * desc?: string * } * type Result = PartialRequired<Agent, 'id' | 'name'>; */ export type PartialRequired<T extends Obj, K extends keyof T> = Expand< { [P in K]-?: T[P]; } & Pick<T, Exclude<keyof T, K>> >;

实现上有三个关键点:

  • { [P in K]-?: T[P] }:对选中的键K做映射,-?修饰符把原本的可选性移除,使这些字段变为必填;
  • Pick<T, Exclude<keyof T, K>>:把其余字段原样保留(可选性不变),两者交叉后得到完整对象;
  • 外层再套Expand,让结果以摊平后的对象字面量呈现,避免交叉类型在提示里显得臃肿。

源码注释明确给出使用场景:当服务端类型声明把所有字段都标成可选、而实际接口必填了其中一部分时,用它“纠正”类型声明,而不必复制一份 interface。

3.2 Teamspace 类型(src/teamspace.ts)

teamspace.ts 定义了动态路由参数类型:

export interface DynamicParams extends Record<string, string | undefined> { space_id?: string; bot_id?: string; plugin_id?: string; workflow_id?: string; dataset_id?: string; doc_id?: string; tool_id?: string; invite_key?: string; product_id?: string; mock_set_id?: string; conversation_id: string; commit_version?: string; /** social scene */ scene_id?: string; post_id?: string; project_id?: string; }

几个使用上的要点:

  • 接口继承Record<string, string | undefined>索引签名,意味着除了枚举出的字段,任意字符串键都能以string | undefined访问,这与真实 URL query 参数的“不可穷举”特性相符;
  • 字段覆盖了 teamspace 场景下的各类资源维度:空间(space_id)、Bot(bot_id)、插件(plugin_id)、工作流(workflow_id)、知识库(dataset_id)、文档(doc_id)、工具(tool_id)、市场商品(product_id)、Mock 集(mock_set_id)、社交场景(scene_id/post_id,源码注释标注为 social scene)、项目(project_id);
  • 唯一必填字段是conversation_id(没有?修饰符),其余均为可选。使用时必须保证会话 ID 一定被提供,否则类型检查不通过;
  • 可选的invite_key用于团队空间邀请链接场景,commit_version用于指定资源版本。

3.3 用户与鉴权类型(src/data_item.d.ts)

data_item.d.ts 以全局declare namespace DataItem组织了一批账号体系数据结构。README 概括为UserInfo与四类鉴权类型,源码中实际提供的接口更完整,此处按功能分组说明。

UserInfo:完整用户信息
interface UserInfo { app_id: number; /** * @Deprecated will lose precision due to overflow, use user_id_str */ user_id: number; user_id_str: string; odin_user_type: number; name: string; screen_name: string; avatar_url: string; user_verified: boolean; email?: string; email_collected: boolean; // ... 其余约 70 个字段 bui_audit_info?: { audit_info: { user_unique_name?: string; avatar_url?: string; name?: string; [key: string]: unknown }; /** int value. 1 During the review, 2 passed the review, and 3 failed the review. */ audit_status: 1 | 2 | 3; details: Record<string, unknown>; is_auditing: boolean; last_update_time: number; unpass_reason: string; }; }

值得注意的实现细节:

  • 精度问题警示user_id: number被显式标注@Deprecated,注释说明大整数在 number 类型下会溢出丢精度,应使用字符串形式的user_id_str。这是对接 64 位 ID 的经典坑,类型注释直接把它固化在声明里;
  • 布尔语义字段大量采用0/1 number表达(如is_blockedis_blockingnew_userhas_password),与后端序列化习惯保持一致,前端不能直接当真值判断;
  • 嵌套的bui_audit_info.audit_status用了字面量联合1 | 2 | 3表示“审核中 / 通过 / 不通过”,源码注释给出了每个取值的含义;
  • 还有sec_user_idold_user_id等历史迁移字段(need_ttwid_migration),说明该结构体长期跟随账号体系演进。
鉴权与账号流程类型

README 列举的四个核心接口在源码中的定义如下:

  • AuthLoginParams—— OAuth 登录入参:platform_app_id(必填)、code/access_token/access_token_secret/openid/profile_key(各 OAuth 平台回传凭证,均可选)、login_onlyextra_params
  • AuthorizeResponse—— 授权响应:包含token与嵌套user_infouser_idapp_idscreen_namemobileemailavatar_urlcreate_timeis_new_useris_new_connectsession_keysession_app_idsafe_mobile等);
  • SendCodeData—— 发送验证码响应:mobilemobile_ticketretry_time(重试冷却时间);
  • UserCheckResponse—— 用户校验响应:value_ticketauthTypeerror_codeoauth_platformsstring[] | null)、platform_user_namesuserType等。

除 README 提到的四个之外,源码中还包含以下接口(可视为同一命名空间的完整能力面):

接口用途关键字段
UserConnectItem第三方平台账号绑定记录platformaccess_tokenopen_idexpired_timeplatform_uid
bindWithEmailLoginParams邮箱(第三方)绑定登录入参platform_app_id(必填)、coderedirect_uri
bindWithMobileLoginParams手机号绑定登录入参platform_app_id(必填)、platformneed_mobilechange_bind
ValidateCodeResponse验证码校验结果ticket
ResetByEmailTicket邮箱重置票据ticket
AuditItem单条审核项passtitletextreason
CancelCheckResponse账号注销前检查business_auditpunish_audituser_permission_auditcancel_ticket
UploadAvatarResponse头像上传结果web_uri

另外从源码结构看,bindWithEmailLoginParams在文件内声明了两次(第 130 行与第 186 行),两次字段结构一致,依赖 TypeScript 的 interface 声明合并(declaration merging)共存,读取该文件时不必将其视为冲突。

3.4 全局模块声明(src/index.d.ts)

index.d.ts 是这个包的“总装配点”,开头通过 triple-slash 引用把其余声明文件与依赖包的类型串起来:

/// <reference types='./data_item' /> /// <reference types='./navigator' /> /// <reference types='./window' /> /// <reference types='@coze-arch/bot-env/typings' />

最后一行引向工作区包@coze-arch/bot-env的 typings(环境相关类型),这也是 README「Dependencies」一节将@coze-arch/bot-env列为开发依赖的原因——它只用于类型检查阶段,不产生运行时依赖。

其后的文件模块声明覆盖了前端资源导入的常见形态:

图片文件.jpeg/.jpg/.webp/.gif/.png):

declare module '*.png' { const value: string; export default value; }

导入后默认为字符串(资源 URL),例如import myImage from './image.png'; // string

样式文件.less/.css):

declare module '*.less' { const resource: { [key: string]: string }; export = resource; }

注意这里用的是export =而非export default,对应 CSS Modules 风格导入:import styles from './styles.less'; // { [key: string]: string }

SVG 文件

declare module '*.svg' { export const ReactComponent: React.FunctionComponent< React.SVGProps<SVGSVGElement> >; /** * The default export type depends on the svgDefaultExport config, * it can be a string or a ReactComponent * */ const content: any; export default content; }
  • 命名导出ReactComponent是固定可用的React.FunctionComponent<React.SVGProps<SVGSVGElement>>import { ReactComponent } from './icon.svg';
  • 默认导出类型刻意声明为any,因为源码注释明确说明其真实类型取决于构建侧svgDefaultExport配置(可能是字符串,也可能是 ReactComponent),声明层不做强断言。这里的React类型来自 devDependencies 中的 React 18.2 类型包。

3.5 浏览器 API 扩展(src/window.d.ts 与 src/navigator.d.ts)

Window 扩展(window.d.ts)声明了 bot 平台在宿主环境中会注入/依赖的一组全局对象:

interface Window { /** IDE plugin iframe mount method for unmounting */ editorDispose?: any; MonacoEnvironment?: any; tt?: { miniProgram: { postMessage: (param: { data?: any; success?: (res) => void; fail?: (err) => void }) => void; redirectTo: (param: { url?: string; success?: (res) => void; fail?: (err) => void }) => void; navigateTo: (param: { url?: string; success?: (res) => void; fail?: (err) => void }) => void; reLaunch: (param: { url?: string; success?: (res) => void; fail?: (err) => void }) => void; navigateBack: (param?: { delta?: number; success?: (res) => void; fail?: (err) => void }) => void; getEnv: (res) => void; }; }; __cozeapp__?: { props: Record<string, unknown>; setLoading?: (loading: boolean) => void; }; }

对应 README 给出的三个典型调用场景:

// IDE 插件支持(iframe 卸载回调) window.editorDispose?.(); // 小程序(tt)容器集成 window.tt?.miniProgram.postMessage({ data: { ... } }); // Coze 宿主 App 集成 window.__cozeapp__?.setLoading?.(true);

从声明结构看,这些扩展刻画了三类宿主环境:IDE 插件宿主(editorDisposeMonacoEnvironment,后者用于 Monaco 编辑器的 worker 环境配置)、字节小程序容器(tt.miniProgram提供postMessage/redirectTo/navigateTo/reLaunch/navigateBack/getEnv六类页面与消息 API)、Coze App 宿主(__cozeapp__.props传参 +setLoading控制全局 loading)。由于全部声明为可选(?),在浏览器独立环境访问它们不会引发类型错误,配合?.调用即可安全降级。

另外,该文件末尾还附加了一个process.env的全局命名空间声明(declare namespace process { const env: { [key: string]: string } }),README 未单独列出,但源码中确实存在,作用是让浏览器侧代码在引用process.env.XXX(由构建工具 DefinePlugin 类机制注入)时通过类型检查。

Navigator 扩展(navigator.d.ts)非常简洁:

interface Navigator { standalone: boolean; }

用于独立 Web App(PWA / 添加到主屏幕)检测:

if (navigator.standalone) { // Running as standalone web app }

standalone声明为非可选字段,即该包假定运行环境总会提供此属性。

四、工程化:构建、检查与扩展

4.1 项目结构

src/ ├── index.d.ts # 主类型定义与文件模块声明(总装配点) ├── common.ts # 通用工具类型与枚举(唯一含运行时产出的文件) ├── teamspace.ts # Teamspace 动态路由参数 ├── data_item.d.ts # DataItem 命名空间:用户与鉴权类型 ├── navigator.d.ts # Navigator 扩展 └── window.d.ts # Window 扩展与 process.env 声明

六个文件与 README 描述一一对应,职责划分清晰:全局副作用声明放.d.ts,需要值导出的放.ts

4.2 构建:No-op 是设计使然

package.json 中的脚本定义:

"scripts": { "build": "exit 0", "lint": "eslint ./" }

build就是exit 0——因为包内只有类型声明(以及一个轻量枚举),消费方直接编译其.ts源文件即可,不需要产物步骤。类型层面的质量保障由 TypeScript 项目引用(project references)承担:tsconfig.json 是一个 solution 文件,"composite": true并引用./tsconfig.build.json与 tsconfig.misc.json 两个子项目,同时exclude: ["**/*"]保证 solution 层不重复包含源文件。Rush 侧则在 config/rush-project.json 中注册了ts-check操作(输出目录./dist),由仓库统一的rushx ts-check流程执行整仓类型检查。

Lint 使用共享配置@coze-arch/eslint-config(devDependency),本地配置见 eslint.config.js;源码中Obj定义处的// eslint-disable-next-line @typescript-eslint/no-explicit-any -- had to any注释体现了该包对any的克制态度——只在确实无法避免(如svgDefaultExport的不确定默认导出、tt小程序回调参数)时才放行。

4.3 新增类型的规范

README「Adding New Types」给出四条规则,对照包结构可以落地为:

  1. 文件模块声明(新的资源后缀)→ 加入 src/index.d.ts;
  2. 通用工具类型→ 加入 src/common.ts;
  3. 领域类型→ 新建文件(如 teamspace 那样),并在package.jsonexportstypesVersions中登记子路径;
  4. 全局扩展(window / navigator 等 DOM 全局对象)→ 分别加入 src/window.d.ts 或 src/navigator.d.ts,并通过index.d.ts/// <reference types=... />保证被主入口拉起。

最后一条(更新exports字段)是容易遗漏的一步:exports字段存在时,未登记的子路径会被 Node/TS 解析器直接拒绝,typesVersions的兜底映射也要同步维护,否则不同解析策略下会出现“本地能过、消费方报模块找不到”的不一致。

五、依赖与版本前提

运行时依赖

无。该包不含可执行逻辑依赖,dependencies为空。

开发依赖(类型检查阶段)

依赖版本用途
@coze-arch/bot-envworkspace:*提供环境相关 typings,被index.d.ts@coze-arch/bot-env/typings引用
@coze-arch/eslint-configworkspace:*共享 ESLint 配置
@coze-arch/ts-configworkspace:*共享 TypeScript 基配置
typescript~5.8.2类型编译器
react/react-dom~18.2.0提供React.FunctionComponent等类型(用于 SVG 声明)
@types/node^18Node 侧类型
webpack/@rspack/core~5.91.0/0.6.0与构建工具相关的类型环境

适用前提小结:该包面向 coze-studio 的 Rush + pnpm workspace 环境,消费方 TypeScript 需能解析.ts源文件(monorepo 内通过 workspace 链接天然满足);svgDefaultExport等构建侧行为影响 SVG 默认导出的实际类型,声明层已按any兼容处理。

六、小结

@coze-arch/bot-typings用六个文件、零运行时依赖的方式,把 coze-studio bot 前端的类型契约收敛到一个包内:index.d.ts作为全局声明的装配入口,common.ts提供Expand/PartialRequired这类可直接复用的类型工具,teamspace.ts固化动态路由参数契约(conversation_id必填),data_item.d.ts覆盖账号与鉴权的完整数据面(含 64 位 ID 精度、审核状态码等真实业务约束),window.d.ts/navigator.d.ts则把 IDE 插件、小程序容器、Coze App 宿主三类运行环境的桥接 API 类型化。对于要在该 monorepo 中新增或修改 bot 相关前端的开发者,正确的姿势是优先复用这些类型而非在业务包里重新声明,并按「Adding New Types」的分工规则向对应文件补充新契约。

【免费下载链接】coze-studioAn AI agent development platform with all-in-one visual tools, simplifying agent creation, debugging, and deployment like never before. Coze your way to AI Agent creation.项目地址: https://gitcode.com/GitHub_Trending/co/coze-studio

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/13 10:11:00

轻量智能数据架构:用SQLite+Webhook解决重复录入与对账难题

1. 项目概述&#xff1a;为什么“轻量部署智能数据架构”不是又一个PPT概念&#xff0c;而是业务一线的真实止痛药 “轻量部署智能数据架构&#xff0c;消除重复录入、消减对账困难”——这标题里没有一个生僻词&#xff0c;但每个字都戳在财务、运营、销售、供应链这些岗位每天…

作者头像 李华
网站建设 2026/9/13 10:06:59

旧手机变服务器:Termux+宝塔面板+Docker实战指南

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/9/13 10:04:43

IIS强制HTTP跳转HTTPS的三种方案与常见问题排查

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/9/13 9:57:22

验证弹出的那0.5秒,你的流程正在经历什么

验证弹出的那0.5秒&#xff0c;你的流程正在经历什么 一个很少被讨论的细节&#xff1a;从验证弹出到你的流程「意识到验证存在」&#xff0c;中间发生了什么&#xff1f; 有卖家晒过自己的脚本日志&#xff1a;验证弹了47秒后脚本才报错退出。47秒里发生了什么&#xff1f;页…

作者头像 李华