ARTICLE DETAIL

资讯详情

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

TypeSpec 0.66 版本解析:@discriminated 判别联合重构与 1.0-rc 前的语言清理

TypeSpec 0.66 版本解析:@discriminated 判别联合重构与 1.0-rc 前的语言清理 TypeSpec 0.66 版本解析discriminated 判别联合重构与 1.0-rc 前的语言清理【免费下载链接】typespec项目地址: https://gitcode.com/GitHub_Trending/ty/typespecTypeSpec 0.662025 年 3 月发布是一次为 1.0-rc0 做准备的清理型版本它引入全新的discriminated装饰器以统一并简化判别联合Discriminated Union的写法同时移除了一批即将过期的旧语法包括字符串形式可见性、基于类型的装饰器参数、以及discriminator用于联合等。阅读本文后你将掌握discriminated的完整用法与序列化规则、新编译进度指示器的行为以及 0.66 中全部破坏性变更与弃用项的迁移路径可直接据此升级存量 TypeSpec 项目。注意本版本包含大量将在下一版本中移除的弃用项deprecations。官方在发布说明中明确警告由于正在筹备 1.0-rc0TypeSpec 语言及部分库正在进行清理。一、新特性discriminated判别联合1.1 背景与动机此前TypeSpec 中定义带判别器的联合需要借助discriminator装饰器它基于继承体系工作判别器属性必须显式写在每个模型上且判别值由模型属性的字面量值决定。这种方式对使用者不够直观也容易在派生模型体系中出错。0.66 引入了全新的discriminated装饰器目标是提供更简单、更符合直觉的判别联合体验直接以联合变体名variant name作为判别值无需在每个模型上重复声明判别属性。1.2 基本用法discriminated union Pet { cat: Cat, dog: Dog, }该联合的变体cat与dog直接决定了序列化后的判别值。默认情况下discriminated使用**信封对象envelop object**包装联合序列化结果如下{ kind: cat, value: { name: Whiskers, meow: true } }, { kind: dog, value: { name: Rex, bark: false } }其中外层kind是判别属性discriminator property内层value承载实际的变体模型数据。这种信封形式保证了多个联合变体在序列化层拥有统一的形状便于下游解析。1.3 底层默认值源码级解读从编译器实现可以看到discriminated的完整默认选项。在 packages/compiler/src/lib/decorators.ts 中discriminatedDecorator的实现为export const discriminatedDecorator: DiscriminatedDecorator ( context: DecoratorContext, entity: Union, options: DiscriminatedOptions {}, ) { setDiscriminatedOptions(context.program, entity, { envelope: object, discriminatorPropertyName: kind, envelopePropertyName: value, ...options, }); const [_, diagnostics] getDiscriminatedUnion(context.program, entity); context.program.reportDiagnostics(diagnostics); };即默认配置为选项默认值含义envelopeobject序列化时使用信封对象包裹变体设为none则不做包裹discriminatorPropertyNamekind判别属性名envelopePropertyNamevalue信封中承载变体数据的属性名应用装饰器后编译器会立即调用getDiscriminatedUnion对联合做校验并将产生的诊断diagnostics上报到程序确保非法写法在编译期即被拦截。1.4 校验规则源码级解读校验逻辑位于 packages/compiler/src/core/helpers/discriminator-utils.ts 的getDiscriminatedUnionForUnion函数核心规则如下变体名必须是字符串只有字符串命名的变体才会被登记为判别联合的变体若出现匿名变体typeof variant.name ! string则将其视为默认变体defaultVariant且只允许存在一个否则报duplicateDefaultVariant诊断。envelope: none时每个变体必须是模型未使用信封包裹时每个变体的类型必须是Model否则报noEnvelopeModel诊断。判别属性值必须与变体名一致当envelope: none时若变体模型上恰好声明了名为判别属性如默认的kind的属性编译器会校验其字符串字面量值是否等于该变体名不匹配则报discriminantMismatch诊断。这保证了变体名即判别值这一约定在无信封模式下同样成立。1.5 与旧discriminator的迁移对于此前在联合上使用discriminator的代码应迁移到discriminated-discriminator(type) discriminated(#{envelope: none, discriminatorPropertyName: type}) union Pet;由于新装饰器默认启用信封且判别属性名为kind若要完全复现旧的无信封、判别属性名为type行为需要像上面这样显式传入envelope: none与discriminatorPropertyName: type。注意参数使用的是 TypeSpec 的值语法#{...}而非模型表达式语法。注意discriminator本身并未消失——它仍可继续用于模型继承体系下的判别对应getDiscriminatedUnionFromInheritance这条路径见 discriminator-utils.ts被弃用的仅是在联合union上使用discriminator这一场景。二、新特性tsp compile编译进度指示器0.66 为tsp compile命令加入了编译进度指示器实时显示当前所处的编译阶段。编译中会以旋转动画 绿色对勾的方式展示进度$ tsp compile . TypeSpec compiler v0.65.3 ✔ Compiling ⠙ typespec/openapi3其中⠙表示某个 emitter如typespec/openapi3仍在执行中。编译完成后所有阶段都会显示为对勾并输出成功信息$ tsp compile . TypeSpec compiler v0.65.3 ✔ Compiling ✔ typespec/openapi3 Compilation completed successfully.该指示器对应源码中新增的以当前编译阶段显示进度能力对应 PR #6082让长耗时编译过程不再无响应。若你正在编写 CI 脚本或希望保留纯文本输出可留意tsp compile的日志/输出选项将进度指示器输出与机器可读日志区分处理。三、破坏性变更typespec/openapi3的{service-name}插值语义0.66 对tspconfig.yaml中{service-name}占位符的语义做了破坏性变更PR #6182现在{service-name}总是插值为当前服务名current service name若你希望保留旧行为仅在存在多个服务时才插值服务名否则保持占位符原样应改用{service-name-if-multiple}。典型场景是输出文件名、目录结构等 emitter 配置中引用服务名的位置。升级到 0.66 后请检查tspconfig.yaml中所有使用{service-name}的地方确认是否符合预期语义必要时替换为{service-name-if-multiple}。四、弃用项与迁移指南Deprecations0.66 的核心主题是为 1.0-rc0 清理语言与库因此本轮弃用项数量多且影响面广以下逐一说明迁移路径。4.1typespec/compiler1联合上的discriminator弃用PR #6059详见上文 1.5 节迁移到discriminated。2字符串形式可见性修饰符弃用PR #6088此前可见性可用字符串字面量表示例如visibility(create, read) example: string;现在应改用Lifecycle枚举成员visibility(Lifecycle.Create, Lifecycle.Read) example: string;完整映射表如下旧写法字符串新写法枚举成员createLifecycle.CreatereadLifecycle.ReadupdateLifecycle.UpdatedeleteLifecycle.DeletequeryLifecycle.Query特别地visibility(none)应替换为invisible(Lifecycle)visibility(none) example: string;等价于invisible(Lifecycle) example: string;3无参parameterVisibility弃用PR #6088无参的parameterVisibility原本的作用是关闭有效的 PATCH 可选性effective PATCH optionality即阻止typespec/http把请求体的所有属性都当作有效可选处理。例如parameterVisibility patch op example(bodyRoot resource: Resource): Resource;现在应显式声明这一意图patch(#{ implicitOptionality: false }) op example(bodyRoot resource: Resource): Resource;即通过patch的新选项implicitOptionality: false来关闭 PATCH 隐式可选行为。4service装饰器改为接收值PR #6108service的参数从模型表达式迁移到值语法-service({title: My service}) service(#{title: My service})4.2typespec/httpheader装饰器更新接受值语法并新增explode选项PR #6130header的传参方式同步迁移到值语法同时使用模型表达式语法传参、以及使用format字段的写法均已弃用op example1( - header({ name: ETag }) etag: string header(#{ name: ETag }) etag: string ): void; op example2( - header({ format: csv }) list: string[] header list: string[] ): void;example2中原本依赖format: csv的写法0.66 起直接以数组类型 默认序列化方式表达即可不再通过format字段指定 CSV 格式。同时explode选项用于控制 header 数组/对象的展开序列化方式typespec/openapi3已同步支持headers的explode选项PR #6130。4.3typespec/openapi1extension装饰器三处变更PR #6078移除扩展名必须以x-开头的限制——现在可以注册任意名称的扩展支持传入值value以输出原始数据raw data对传入类型type增加弃用警告——未来版本中传入类型将输出为 OpenAPI schema。标量字面量字符串、布尔、数字会被自动视为值无需改造但模型表达式与元组表达式必须转换为值语法才能在后续版本中保持当前行为-extension(x-obj, { foo: true }) extension(x-obj, #{ foo: true }) -extension(x-tuple, [ foo ]) extension(x-tuple, #[ foo ]) model Foo {}注意元组使用#[ ... ]前缀表示值元组与普通模型/元组表达式区分。2info装饰器改为接收值PR #6108与service相同info的参数语法从模型表达式迁移到值语法-info({ version: 1.0.0 }) info(#{ version: 1.0.0 })多字段场景同样迁移-info({ info(#{ termsOfService: http://example.com/terms/, - contact: { contact: #{ name: API Support, url: http://www.example.com/support, email: supportexample.com }, })嵌套对象如contact也要改成值语法#{ ... }。统一规律0.66 中service、info、header、extension的传参全部从模型表达式/类型迁移到值语法。这是 TypeSpec 语言向 1.0 演进中的一项系统性清理目的就是区分类型参数与值参数两种装饰器参数语义。五、Features 一览按包划分5.1typespec/compiler联合类型支持模型属性的自动补全PR #5483。为多种三引号字符串语法问题新增代码修复codefixPR #5458。新增list-files标志用于记录并输出所有已发射emitted的文件PR #6082。新增编译进度指示器展示tsp compile当前阶段PR #6082。新增discriminated装饰器用于表达带隐式信封的判别联合PR #6059。语言服务器Language Server报告未使用的模板参数PR #5494。tsp init重新设计与简化PR #6045。新增Typekits 以支持 EFV2Emitter Framework V2PR #5996。tsp init模板中 config 与 emitter 合并写入tspconfig.yamlPR #5986。--version显示是否运行在 standalone 版本PR #6047。语言服务器报告未使用的usingPR #5453。包typespec/http-server-javascript更名为typespec/http-server-jsPR #6164。5.2typespec/httpEmitter Framework V2EFV2落地PR #5996。这是 emitter 编写框架的一次重大演进typespec/html-program-viewer同步迁移到 EFV2PR #5996。5.3typespec/openapi3支持新的discriminated联合PR #6059。新增seal-object-schemasemitter 选项PR #5994自动在尽可能多的位置将additionalProperties/unevaluatedProperties设置为{ not: {} }。JsonSchema 与 OpenAPI 3.1 emitter 改用unevaluatedProperties替代additionalPropertiesOpenAPI 3 emitter 对齐 JsonSchema 行为将Recordnever视为设置additionalProperties: { not: {} }PR #5961。同步支持headers的explode选项并采用值语法PR #6130。共享操作shared operations的operationId当多个操作通过operationId提供相同值时现在可以统一设置PR #6157。在 API 面API surface中暴露核心库类型PR #6006。关于seal-object-schemas从 packages/openapi3/src/lib.ts 可以看到该选项的完整定义seal-object-schemas: { type: boolean, nullable: true, default: false, description: [ If true, then for models emitted as object schemas we default additionalProperties to false for, OpenAPI 3.0, and unevaluatedProperties to false for OpenAPI 3.1, if not explicitly specified elsewhere., Default: false, ].join(\n), },其默认值为false开启后对于被发射为对象 schema 的模型若未显式指定则 OpenAPI 3.0 中默认additionalProperties为 false、OpenAPI 3.1 中默认unevaluatedProperties为 false。实际发射逻辑位于 packages/openapi3/src/schema-emitter.ts仅当sealObjectSchemas开启且模型没有派生模型!derivedModels.length时才应用该约束——即有继承关系的模型不会被自动封口避免破坏多态。5.4typespec/json-schema新增seal-object-schemasemitter 选项PR #5994行为与typespec/openapi3一致。与 openapi3 相同的unevaluatedProperties行为变更PR #5961。5.5 编辑器扩展typespec-vs支持在 Visual Studio 中为tspconfig.yaml提供 IntelliSensePR #5968。typespec-vscode资源管理器右键菜单新增Import TypeSpec from OpenApi3菜单项可从 OpenAPI 3 文档导入 TypeSpecPR #6014同步响应typespec/http-server-javascript→typespec/http-server-js的包名变更PR #6164。六、Bug Fixes 一览按包划分6.1typespec/compiler**增强表达式augmenting an expression**现在会报错而不是静默失败PR #4926。修复StringTemplate类型在typespecValueToJson中不受支持的问题PR #5937。修复example在使用混合元数据http模型时报告可赋值性错误的问题PR #6204。修复转义标识符前使用装饰器时 tmlanguage 语法高亮异常PR #6125。修复tsp info崩溃PR #6192。修复mutator 未变更sourceModel(s)的问题PR #6203。6.2typespec/openapi3修复typespec/openapi3/invalid-component-fixed-field-key诊断指向错误目标的问题PR #5901。6.3 typespec-vscode修复union 代码片段code snippet错误PR #6137。七、升级清单总结综合全文从 0.65 升级到 0.66 时建议按以下顺序自查联合上的判别全局搜索discriminator用于union的代码迁移到discriminated注意信封与判别属性名的默认值。可见性修饰符将字符串形式create/read/update/delete/query/none迁移到Lifecycle枚举与invisible(Lifecycle)。装饰器传参语法service、info、header、extension的参数统一改为值语法#{...}/#[...]。PATCH 隐式可选性无参parameterVisibility改为patch(#{ implicitOptionality: false })。tspconfig.yaml占位符检查{service-name}语义是否符合预期必要时改用{service-name-if-multiple}。emitter 行为差异确认seal-object-schemas、unevaluatedProperties变更是否影响已生成文档关注headers的explode选项。包名变更typespec/http-server-javascript已更名为typespec/http-server-js相关依赖与导入路径需同步更新。作为面向 1.0-rc0 的清理版本0.66 的核心信号非常明确TypeSpec 正在把装饰器参数体系收敛到值这一单一语义并用更直观的discriminated统一判别联合体验。尽早完成上述迁移可以为后续 1.0 正式版的升级减少阻力。【免费下载链接】typespec项目地址: https://gitcode.com/GitHub_Trending/ty/typespec创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表