ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

Dagger TypeScript SDK 中 ListTypeDefID 类型别名解析:列表类型定义标识符的底层设计与实战

Dagger TypeScript SDK 中 ListTypeDefID 类型别名解析:列表类型定义标识符的底层设计与实战 Dagger TypeScript SDK 中 ListTypeDefID 类型别名解析列表类型定义标识符的底层设计与实战【免费下载链接】daggerAutomation engine to build, test and ship any codebase. Runs locally, in CI, or directly in the cloud项目地址: https://gitcode.com/GitHub_Trending/da/dagger导读ListTypeDefID是 Dagger TypeScript SDKdagger.io/dagger在模块类型系统Module TypeDef中用于唯一标识列表类型定义ListTypeDef对象的标量scalar类型别名。本篇文章以 Dagger 官方 API 参考文档中ListTypeDefID类型别名的声明为骨架结合仓库中 TypeScript SDK 生成代码与 Go 核心实现core/typedef.go展开讲解它是什么、与ListTypeDef的关系、Dagger 如何用 branded string 实现类型安全、以及在实际模块开发中如何获取与使用这类 ID。读完本文你将能理解 Dagger 类型定义体系中对象类型 ↔ 标识符的映射规律并能在自建 Dagger 模块中正确编写基于类型定义 ID 的查询与转换代码。一、文档原文ListTypeDefID 类型别名的声明在 Dagger 的 TypeScript API 参考文档中ListTypeDefID被定义在api/client.gen.ts模块之下其完整声明如下type ListTypeDefID string object官方文档对它的语义说明是TheListTypeDefIDscalar type represents an identifier for an object of typeListTypeDef.也就是说ListTypeDefID并不是普通字符串而是 Dagger GraphQL API 中ListTypeDef对象类型的标识符ID标量。在 Type Declaration 部分它还带有一个辅助成员__ListTypeDefID其类型为never——这是一个phantom 字段用于在类型层面将ListTypeDefID与其他同样基于string的 ID 类型区分开保证编译器不会允许你把一个ObjectTypeDefID误传给期望ListTypeDefID的位置。需要注意的是这份文档本身是一页极简的 API 参考条目篇幅很短但其背后关联着 Dagger 完整的模块类型定义TypeDef体系。下面我们将从类型别名本身出发逐层深入到生成代码与 Go 内核实现。二、ListTypeDefID 指向的对象ListTypeDef 是什么要理解ListTypeDefID首先必须理解它标识的目标对象ListTypeDef。在 Dagger 的类型定义体系中ListTypeDef表示Module 中一种列表类型的定义其核心结构在 Go 内核 core/typedef.go 中一目了然type ListTypeDef struct { ElementTypeDef dagql.ObjectResult[*TypeDef] }即一个ListTypeDef只有唯一一个关键属性元素类型ElementTypeDef——也就是这个列表里的每个元素是什么类型标量、对象、枚举等由TypeDef描述。ListTypeDef自身的 GraphQL 类型描述为A definition of a list type in a Module.在 Go 侧ListTypeDef实现了dagql.PersistedObject与dagql.HasDependencyResults接口core/typedef.go这意味着它可以被序列化为持久化对象、并在加载时重新附加其依赖结果即ElementTypeDef所引用的元素类型定义。在 TypeScript 生成的客户端中对应类为ListTypeDefsdk/typescript/src/api/client.gen.ts对外暴露两个能力id()返回该ListTypeDef的唯一标识符返回值类型正是ID即ListTypeDefIDelementTypeDef()返回列表的元素类型定义TypeDef对象。/** * A definition of a list type in a Module. */ export class ListTypeDef extends BaseClient { // ... /** * A unique identifier for this ListTypeDef. */ id async (): PromiseID { ... } /** * The type of the elements in the list. */ elementTypeDef (): TypeDef { ... } }三、ListTypeDef 在 TypeDef 体系中的位置AsList 与 WithListOfListTypeDef并不是孤立存在的它始终依附于一个统一的TypeDef联合类型。Go 内核中TypeDef结构体core/typedef.go同时承载了六种类型的定义type TypeDef struct { Name string Kind TypeDefKind Optional bool AsList dagql.Nullable[dagql.ObjectResult[*ListTypeDef]] AsObject dagql.Nullable[dagql.ObjectResult[*ObjectTypeDef]] AsInterface dagql.Nullable[dagql.ObjectResult[*InterfaceTypeDef]] AsInput dagql.Nullable[dagql.ObjectResult[*InputTypeDef]] AsScalar dagql.Nullable[dagql.ObjectResult[*ScalarTypeDef]] AsEnum dagql.Nullable[dagql.ObjectResult[*EnumTypeDef]] }当某个TypeDef的Kind为TypeDefKindList时其AsList字段便指向对应的ListTypeDef。构造列表类型定义的方法定义在 core/typedef.gofunc (typeDef *TypeDef) WithListOf(list dagql.ObjectResult[*ListTypeDef]) *TypeDef { typeDef typeDef.WithKind(TypeDefKindList) typeDef.AsList dagql.NonNull(list) return typeDef.syncName() }因此在 GraphQL 查询层面典型的列表类型定义查询形态是先取得某个TypeDef然后asList分支取出ListTypeDef再调用其id字段获得ListTypeDefID。TypeScript 客户端同样提供了asList()方法sdk/typescript/src/api/client.gen.ts它负责把 TypeDef 的 GraphQL 选择节点切换到ListTypeDefasList async (): PromiseListTypeDef | null { const ctx this._ctx.select(asList) const response: Awaited... await ctx.execute() return new ListTypeDef(ctx.copy().selectNode(response, ListTypeDef)) }四、Dagger 的 ID 体系为什么用string object而不是普通 stringListTypeDefID的声明string object是 Dagger 各 SDK 中所有 ID 类型的共同模式。在 sdk/typescript/src/api/client.gen.ts 中可以找到 ID 类型的基座定义export type ID string { __ID: never }这种被称为branded type标记类型的手法有两个直接收益运行时就是普通字符串ID 在 GraphQL 传输、持久化缓存、URL 传递中都表现为普通字符串不会引入任何额外运行时开销编译期类型隔离通过附加一个never类型的 phantom 字段__ListTypeDefID使ListTypeDefID与ObjectTypeDefID、TypeDefID等在结构上互不兼容。任何将一种 ID 当作另一种 ID 使用的代码都会在编译阶段被 TypeScript 拒绝从而避免把模块 A 的对象 ID误当作模块 B 的对象 ID传给引擎。同样的模式也体现在 Go 生成的 SDK 中。sdk/typescript/runtime/internal/dagger/dagger.gen.go 中生成了与之对应的 Go 定义type ListTypeDefID string以及根据 ID 重建对象的方法sdk/typescript/runtime/internal/dagger/dagger.gen.gofunc (r *Query) LoadListTypeDefFromID(id ListTypeDefID) *ListTypeDef { ... }这体现了 Dagger ID 设计的一条通用规律每种对象类型 X 都配套一个XID类型与一个LoadXFromID入口ListTypeDefID正是这条规律在列表类型定义上的实例。在 TypeScript 客户端中对应loadListTypeDefFromID其底层会构造query.listTypeDef(id)形式的 GraphQL 查询。五、实战在 Dagger 模块代码中使用 ListTypeDefID基于上文的结构分析实际开发中围绕ListTypeDefID的典型操作包括以下几个环节。5.1 通过 TypeDef 的 asList 分支获取 ID当你在模块运行时拿到了一个模块的类型定义例如通过moduleType().definitions()遍历模块暴露的类型对于Kind为列表的类型可以这样取得其标识符const typeDef ... // 某个 TypeDef 对象 const listDef await typeDef.asList() if (listDef) { const listId: ID await listDef.id() // 类型即 ListTypeDefID const element listDef.elementTypeDef() // 元素的类型定义 }5.2 从 ID 反查对象ID 反序列化ListTypeDefID是可持久化的Dagger 引擎会把ListTypeDef编码为 ID 字符串保存对应 Go 侧的encodePersistedListTypeDef/decodePersistedListTypeDef见 core/typedef.go随后你可以仅凭 ID 把对象反查回来const listDef client.loadListTypeDefFromID(listId)这一机制的意义在于跨会话、跨 GraphQL 查询传递模块类型信息时只需要传递一个不透明的 ID 字符串而不必重新执行整棵类型依赖树查询。这也是 Dagger 把 ID 命名为identifier for an object的根本原因——它等价于对象在持久化缓存中的寻址句柄。5.3 结合元素类型构造自定义列表类型在模块类型注册/内省introspection流程中TypeScript SDK 的注册器会处理ListTypeDef与TypeDef之间的转换sdk/typescript/src/module/entrypoint/register.tsreturn dag.typeDef().withListOf(addTypeDef((type as ListTypeDef).typeDef))其中withListOf正是对应 Go 内核WithListOf的 GraphQL 构造方法——传入一个列表类型定义其标识符为ListTypeDefID得到完整的列表TypeDef。ListTypeDefID在这里承担了模块类型注册图中列表节点句柄的角色使得递归定义的元素类型可以被安全地引用与复用。六、易混淆点与注意事项ListTypeDefID≠TypeDefIDTypeDefID标识的是统一类型定义对象而ListTypeDefID只标识其中Kind list的那一层结构。得益于 branded type二者在 TypeScript 中不能混用这正是该设计要避免的经典错误。ID 是引擎侧生成的客户端一般不需要也不应该手工构造ListTypeDefID字符串应始终通过id()字段或loadListTypeDefFromID获取/消费。ID 依赖引擎会话ID 指向持久化缓存中的对象跨引擎实例传递 ID 时需保证该对象已被持久化persisted否则反序列化会失败。该文档为自动生成的 API 参考api/client.gen.ts与dagger.gen.go均由 Dagger 的 codegen 从核心 GraphQL Schema 生成ListTypeDefID的定义以当前仓库version-0.19版本对应的 SDK 为准。总结ListTypeDefID表面上是 TypeScript 中一行简单的类型别名声明string object其背后却是 Dagger 模块类型系统的一整套 ID 设计ListTypeDef承载列表类型定义与元素类型引用ListTypeDefID通过 branded string 技术实现编译期类型安全与运行期零开销Go 内核core/typedef.go与各 SDK 生成代码sdk/typescript/src/api/client.gen.ts共同保证了 ID 的获取、持久化与反序列化闭环。理解这一类型别名也就掌握了 Dagger 中对象 ↔ ID泛化机制的入口对你编写、内省与调试自己的 Dagger 模块类型定义会有直接的帮助。【免费下载链接】daggerAutomation engine to build, test and ship any codebase. Runs locally, in CI, or directly in the cloud项目地址: https://gitcode.com/GitHub_Trending/da/dagger创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表