TypeSpec 流式协议装饰器 `@streamOf` 完全指南:`@typespec/streams` 库的声明、实现与消费链解析 TypeSpec 流式协议装饰器streamOf完全指南typespec/streams库的声明、实现与消费链解析【免费下载链接】typespec项目地址: https://gitcode.com/GitHub_Trending/ty/typespecstreamOf是typespec/streams库导出的核心装饰器用于把一个 TypeSpec 模型标记为流式协议类型并声明该流底层承载的数据类型。本文以 decorators.md 参考文档为主体结合本仓库packages/streams的.tsp声明、TS 实现与测试用例以及packages/http中HttpStream/JsonlStream的消费方式系统讲解streamOf的完整用法、底层原理与真实调用链。读完你将掌握如何声明自定义流类型、如何通过getStreamOf/isStream在编译器层面读取流元数据以及如何像 HTTP 库那样基于它构建高层协议类型。文档定位由 tspd 自动生成的装饰器参考website/src/content/docs/docs/libraries/streams/reference/decorators.md是typespec/streams库的装饰器 API 参考文档属于TypeSpec.Streams命名空间。它并非手写维护而是通过tspd doc工具从源码注释自动生成——这一点可以从 streams/package.json 的脚本得到印证regen-docs: tspd doc . --enable-experimental --llmstxt --output-dir ../../website/src/content/docs/docs/libraries/streams/reference也就是说文档中呈现的签名、参数表与示例直接来源于 lib/decorators.tsp 中extern dec声明上方的 JSDoc 注释。因此这份参考文档是该库当前版本的单一事实来源任何对装饰器行为的深入理解都应回到源码与测试中验证。streamOf装饰器 API 速览参考文档给出streamOf的完整定义它用于指定一个模型代表某种流式协议类型其底层数据由Type参数描述。签名TypeSpec.Streams.streamOf(type: unknown)在.tsp源码中对应的外部声明为见 lib/decorators.tspextern dec streamOf(target: Model, type: unknown);Target作用目标Target说明Model只能应用于模型类型表示该模型是一个流协议类型Parameters参数名称类型描述typeunknown描述该流底层数据的类型官方示例参考文档给出的最小完整示例model Message { id: string; text: string; } streamOf(Message) model Response { body body: string; }这个示例表达了两层语义Message是流中逐条承载的业务数据结构含id、text两个字段Response被标记为流协议类型其流里的数据是Message而body body: string描述的是该流在传输层wire format上的编码载体。Type参数为什么是unknown而不是限定为Model从实现与 HTTP 消费方的用法看它既可以是模型也可以是标量如streamOf(string)甚至是union因此声明为unknown保留了最大的灵活性。声明层extern dec与文档注释的对应关系在 lib/decorators.tsp 中streamOf的完整 JSDoc 注释与参考文档逐字对应/** * Specify that a model represents a stream protocol type whose data is described * by Type. * * param type The type that models the underlying data of the stream. * * example * model Message { * id: string; * text: string; * } * * streamOf(Message) * model Response { * body body: string; * } */ extern dec streamOf(target: Model, type: unknown);extern dec表示该装饰器由宿主实现TypeScript 侧提供。注意文件首行using TypeSpec.Reflection;——这是extern dec声明所需的基础命名空间导入。实现层状态映射与getStreamOf/isStreamstreamOf的运行时实现位于 src/decorators.ts完整代码如下import type { Model, Program, Type } from typespec/compiler; import { useStateMap } from typespec/compiler/utils; import type { StreamOfDecorator } from ../generated-defs/TypeSpec.Streams.js; import { StreamStateKeys } from ./lib.js; const [getStreamOf, setStreamOf] useStateMapModel, Type(StreamStateKeys.streamOf); export const $streamOfDecorator: StreamOfDecorator (context, target, type) { setStreamOf(context.program, target, type); }; export function isStream(program: Program, target: Model): boolean { return getStreamOf(program, target) ! undefined; } export { getStreamOf };关键实现事实状态存储通过编译器工具函数useStateMapModel, Type创建了一个以模型为键、以类型为值的映射键名为StreamStateKeys.streamOf在 src/lib.ts 中注册为State for the streamOf decorator.。useStateMap会把状态挂载到Program上因此是编译期可查询的元数据而非运行时反射。装饰器回调$streamOfDecorator只是把target模型与type参数写入映射本身不做任何校验或代码生成。查询 APIgetStreamOf(program, model)返回该模型关联的流数据类型无标注时返回undefinedisStream(program, model)返回布尔值判断该模型是否为流协议类型。这两个函数是该库对外的核心编程接口见 src/index.ts 的导出。$decorators注册表src/tsp-index.ts把装饰器绑定到命名空间export const $decorators { TypeSpec.Streams: { streamOf: $streamOfDecorator, }, };结合 lib/main.tsp 的导入顺序import ../dist/src/tsp-index.js→./decorators.tsp→./types.tsp可以推断编译 TypeSpec 时先注册 TS 实现再解析.tsp声明最终将streamOf(...)的调用路由到$streamOfDecorator。内置基类型StreamType的自动标注streamOf的典型使用场景是作为基类型的元标记被继承复用。lib/types.tsp 中定义了库自带的流基类型namespace TypeSpec.Streams; /** * Defines a model that represents a stream protocol type whose data is described * by Type. * * template Type The type of the streams data. */ doc() streamOf(Type) model StreamType {}StreamType本身就被streamOf(Type)标注。任何通过is StreamX继承它的模型在编译器语义分析后会复制基类型上的装饰器从而自动获得streamOf X的元数据。这正是 test/decorators.test.ts 第三个用例所验证的行为it(is automatically set on the Stream model, async () { const { CustomStream, Message, program } await Tester.compile(t.code model ${t.model(Message)} { id: string, text: string } model ${t.model(CustomStream)} is StreamMessage {} ); expect(getStreamOf(program, CustomStream as Model)).toBe(Message); });测试用例行为的可验证依据test/decorators.test.ts 用三个用例锁定了streamOf的核心契约用例输入断言provides stream protocol typestreamOf(string) model Blob {}getStreamOf返回Scalar/string类型对象returns undefined if model is not decorated普通模型getStreamOf返回undefinedis automatically set on the Stream modelCustomStream is StreamMessagegetStreamOf返回Message模型这三个断言覆盖了装饰器的正向标注、缺省行为与继承传播三个维度说明streamOf的语义是纯元数据声明 可继承传播不产生任何代码生成副作用。下游消费HTTP 库如何基于streamOf构建流类型typespec/streams的价值在其消费方。HTTP 库在 packages/http/lib/streams/main.tsp 中基于StreamType构建了两个可直接使用的流模型import typespec/streams; import ../main.tsp; using TypeSpec.Streams; namespace TypeSpec.Http.Streams; doc() model HttpStreamType, ContentType extends valueof string, BodyType extends bytes | string string is StreamType { header contentType: typeof ContentType; body body: BodyType; } doc() model JsonlStreamType is HttpStreamType, application/jsonl;HttpStreamType, ContentType, BodyType声明contentType请求头与body载体同时通过is StreamType继承streamOf(Type)标注JsonlStreamType固定ContentType application/jsonl描述每行一个 JSON 对象的 JSONL 流。其消费逻辑在 packages/http/src/experimental/streams.ts 的getStreamMetadata中它从 HTTP 操作的 body 属性出发调用getStreamOf(program, model)反查流的底层数据类型并汇总出bodyType、originalType、streamType与contentTypes等流元数据。注意它采用动态import(typespec/streams)并在失败时抛出typespec/streams was not found说明 streams 是 HTTP 库的可选依赖。packages/http/test/streams/streams.test.ts 验证了整条链路model Message { id: string, text: string } model Foo is HttpStreamType Message, ContentType application/jsonl;断言getStreamOf(program, Foo)返回Message、contentType 解析为application/jsonl、body 类型为stringBodyType的默认值。这印证了从streamOf标注到 HTTP 语义提取的完整闭环。安装与使用在任意 TypeSpec 项目中安装该库npm install typespec/streams然后在.tsp源文件中导入并引用命名空间当前仓库中版本为0.86.0见 streams/package.jsontypespec/compiler为其 peerDependency需要一并可用Node.js 版本要求22.0.0import typespec/streams; using TypeSpec.Streams;之后即可在模型中直接使用streamOf(...)、继承StreamT或在编译期通过getStreamOf/isStream编程式读取流元数据。实践要点总结用途单一streamOf只做标记 声明底层数据类型不涉及编码格式、传输协议等细节——那些由消费方如HttpStream的ContentType/BodyType参数负责组合优于重复定义自定义流类型时优先继承StreamType或HttpStreamType, ...利用装饰器的继承传播自动获得streamOf元数据避免手动重复标注编程接口库公开的getStreamOf(program, model)与isStream(program, model)是连接声明层与消费层的桥梁任何需要感知流类型的库都可以仿照 HTTP 库的模式引入文档可再生成若装饰器注释发生变更可通过pnpm regen-docs重新生成 decorators.md保证文档与源码始终一致。【免费下载链接】typespec项目地址: https://gitcode.com/GitHub_Trending/ty/typespec创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考