Javascript is required
最佳实践发布于 2026-07-28审校于 2026-08-085 分钟阅读

OpenAPI/Swagger Schema 到 TypeScript 契约:代码生成与运行时校验

OpenAPI schema 描述接口契约,TypeScript 类型生成则把这份契约投影到编译期。代码生成可以帮助请求和响应共享字段定义,但不会自动验证运行时 JSON,也不能替代 OpenAPI 文档中的 required、nullable、additionalProperties 和 response 语义。本文聚焦 schema 到 TypeScript 契约的边界。

OpenAPISwaggerJSON to TypeScriptCode GenerationRuntime Validation

一、问题概述:生成类型不等于验证响应

OpenAPI 的 required 描述对象属性是否必须出现,nullabletype: ["string","null"] 描述是否允许 null;生成器可能输出 optional 属性或 union。TypeScript 编译器只检查已进入类型系统的代码,网络响应仍然是 unknown。

二、最小复现:OpenAPI schema 与生成的类型关注不同层

下面的 schema 使用 OpenAPI 3.0 风格的 nullable 说明;OpenAPI 3.1 通常使用 JSON Schema 的 type union。实际生成结果取决于版本和生成器配置。

const userSchema = {
  type: "object",
  required: ["id"],
  properties: {
    id: { type: "string" },
    displayName: { type: "string", nullable: true },
  },
};

// A generator may produce:
type User = { id: string; displayName?: string | null };
console.log(userSchema.required); // ["id"]

三、根因:OpenAPI 版本、生成器和运行时各有职责

OpenAPI 3.0 与 3.1 对 nullable 的表达不同,format 也通常是语义提示而非 JavaScript 运行时检查。代码生成器负责读取 schema 并产生类型/客户端,TypeScript 负责编译期约束,运行时校验器才负责检查未知 JSON;三者不能互相替代。

四、推荐方案:以 OpenAPI schema 为单一契约来源

在 CI 中先校验 OpenAPI 文档本身,再按固定版本和生成器配置生成 TypeScript。明确区分 requestBody、parameters、responses、required、readOnly/writeOnly 和 additionalProperties;运行时收到响应后,使用与 schema 对应的 validator,失败时保留路径和原始响应上下文。

五、完整代码:生成的类型之外再做运行时守卫

以下示例展示一个与 schema 对齐的 TypeScript 类型和手写运行时守卫。它不是某个 OpenAPI generator 或 validator 的 API,只说明静态类型与运行时检查需要两层。

type User = {
  id: string;
  displayName?: string | null;
};

function isUser(value: unknown): value is User {
  if (!value || typeof value !== "object" || Array.isArray(value)) return false;
  const record = value as Record<string, unknown>;
  if (typeof record.id !== "string") return false;
  return record.displayName === undefined || record.displayName === null || typeof record.displayName === "string";
}

const payload: unknown = { id: "u-1", displayName: null };
if (!isUser(payload)) throw new Error("Response does not match User schema");
console.log(payload.id); // u-1

六、常见错误方案

从一次 JSON 响应反推 TypeScript 再当成 OpenAPI 契约,会漏掉 required、nullable 和未出现的响应分支;只生成 interface 就直接信任 fetch 返回值,会跳过运行时验证;把 format: date-time 当成 Date 实例,也超出了 OpenAPI schema 通常保证的范围。

七、边界条件:nullable、额外属性与请求/响应差异

OpenAPI 3.0 的 nullable 与 3.1 的 JSON Schema union 需要按版本解释。additionalProperties、readOnly、writeOnly 会影响请求和响应模型;同一组件 schema 在不同 operation 中也可能通过引用和组合产生不同有效字段。不要只生成一个扁平接口就忽略这些组合。

八、如何验证自动化链路

先用 OpenAPI 文档工具检查 schema,再生成 TypeScript 并运行 tsc。对请求和响应分别准备缺失 required 字段、null、额外属性、错误类型和合法样本,使用运行时 validator 验证;比较生成结果差异时记录 OpenAPI 版本、生成器版本和配置。

九、FAQ

问:Swagger 和 OpenAPI 是两套完全不同的契约吗?答:Swagger 是 OpenAPI 生态中的历史名称和工具品牌,实际要确认文档版本与 schema 语法。

问:生成 TypeScript 后还需要运行时校验吗?答:需要,网络数据在运行时仍是未知值。

问:format: uuid 会自动变成 UUID 类吗?答:通常只是格式提示,具体生成和运行时行为取决于工具配置。

十、总结

OpenAPI schema 是契约来源,代码生成把它投影为 TypeScript 编译期模型,运行时 validator 才能检查真实 JSON。按 OpenAPI 版本处理 nullable、required、组合和额外属性,分别验证 request/response,并记录生成器配置与文档版本。

来源与延伸阅读

技术审校所依据的规范与权威参考资料。

相关文章

继续阅读

可打开关联的浏览器工具,使用自己的样本验证文中的处理流程。

打开关联工具