You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在TypeScript中结合Zod正确处理可选DTO的类型推断?

问题解决:TypeScript + Zod DTO类型推断错误

问题根源

你的代码中,DtoObject 类型将 params 等属性定义为可选的 z.ZodType | undefined,当你把 getTodoByIdDto 标注为 DtoObject 类型时,TypeScript 会将具体的 Zod Schema 类型“拓宽”为通用的 z.ZodType,导致后续的条件类型无法识别到实际的 Schema 结构,最终推断出 params 类型为 undefined,从而引发赋值错误。

解决方案

方案1:使用DTO创建函数保留Schema类型

通过工具函数创建DTO,避免类型拓宽,让TypeScript自动推断具体的Schema类型:

import { z } from 'zod';

// 用于创建DTO的工具函数,保留具体Schema类型
export function createDto<T extends { body?: z.ZodType; params?: z.ZodType; queryParams?: z.ZodType }>(dto: T) {
  return dto;
}

// 定义DTO,无需手动标注类型,由函数自动推断
export const getTodoByIdDto = createDto({
  params: z.object({
    todoId: z.string().openapi({ example: '1234' }),
  }),
});

// 从DTO中提取数据类型的工具类型
type ExtractDtoTypes<T> = {
  [K in keyof T]: T[K] extends z.ZodType ? z.infer<T[K]> : never;
};

// 生成最终的API请求类型
export type GetTodoById = ExtractDtoTypes<typeof getTodoByIdDto>;

// 现在可以正常赋值,无类型错误
export const sample: GetTodoById = {
  params: {
    todoId: '1234',
  },
};

方案2:使用泛型DtoObject类型

如果你倾向于显式的类型标注,可以定义泛型DtoObject来捕获具体的Schema类型:

import { z } from 'zod';

// 泛型DTO类型,保存每个属性的具体Schema类型
export type DtoObject<
  Body extends z.ZodType | undefined = undefined,
  Params extends z.ZodType | undefined = undefined,
  Query extends z.ZodType | undefined = undefined
> = {
  body?: Body;
  params?: Params;
  queryParams?: Query;
};

// 显式指定泛型类型来定义DTO
export const getTodoByIdDto: DtoObject<undefined, z.ZodObject<{ todoId: z.ZodString }>> = {
  params: z.object({
    todoId: z.string().openapi({ example: '1234' }),
  }),
};

// 提取params的推断类型
export type GetTodoById = {
  params: typeof getTodoByIdDto.params extends z.ZodType ? z.infer<typeof getTodoByIdDto.params> : undefined;
};

// 合法的示例赋值
export const sample: GetTodoById = {
  params: {
    todoId: '1234',
  },
};

处理可选Zod Schema的最佳实践

  1. 避免类型拓宽:不要将具体的Schema实例标注为z.ZodType,而是让TypeScript推断其具体类型,或使用泛型/工具函数保留类型信息。
  2. 复用类型提取逻辑:创建通用的ExtractDtoTypes工具类型,避免为每个DTO重复编写条件类型。
  3. 利用Zod内置能力:Zod的z.infer工具需要具体的Schema类型才能正确工作,避免使用通用的z.ZodType作为输入。

内容的提问来源于stack exchange,提问作者TheSmartMonkey

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.14 05:44:56