TypeScript:如何在嵌套配置对象中推断Zod Schema类型?
要让getNextStep能感知对应步骤的Schema数据类型,核心是要在类型定义中捕获每个步骤Schema的具体泛型类型,而不是笼统地用z.ZodType。下面是修改后的完整代码:
import { z } from "zod"; function createConfig<TSteps extends Record<string, { id: string; schema?: z.ZodType }>>( config: { [K in keyof TSteps]: { id: TSteps[K]["id"]; // 保留原步骤的Schema定义 schema?: TSteps[K]["schema"]; // 根据当前步骤的Schema自动推断data类型,无Schema则为unknown getNextStep?: ( data?: TSteps[K]["schema"] extends z.ZodType<infer TData> ? TData : unknown ) => Exclude<keyof TSteps, K> | null; }; } ) { return config; } // 测试示例 const Config = createConfig({ Step1: { id: "Step1", schema: z.object({ name: z.string() }), // 此时data参数会自动推断为 { name: string } | undefined getNextStep: (data) => { console.log(data?.name); // 类型提示正常 return "Step2"; }, }, Step2: { id: "Step2", schema: z.object({ enabled: z.boolean() }), // 添加getNextStep后,data会推断为 { enabled: boolean } | undefined getNextStep: (data) => { console.log(data?.enabled); return null; }, }, });
关键修改说明
泛型捕获完整配置结构:
将原有的createConfig<TKey extends string>改为createConfig<TSteps extends Record<string, { id: string; schema?: z.ZodType }>>,让TSteps自动推断整个配置对象的详细类型,包括每个步骤Schema的具体泛型参数。条件类型提取Schema数据类型:
在getNextStep的参数定义中,通过TSteps[K]["schema"] extends z.ZodType<infer TData> ? TData : unknown实现类型推断——如果当前步骤存在Schema,就提取其泛型参数TData作为data的类型;无Schema则 fallback 到unknown。保留原有返回值约束:
继续使用Exclude<keyof TSteps, K> | null确保getNextStep只能返回其他步骤的键或null,维持原有的类型校验逻辑。
原代码无法推断类型的原因
原Config<TKey>类型中,schema?: z.ZodType未指定具体泛型参数,TypeScript无法从抽象的z.ZodType中提取对应的数据类型,只能将data解析为unknown。修改后通过泛型捕获每个步骤的Schema具体类型,再用条件类型提取数据类型,即可实现自动推断。
内容的提问来源于stack exchange,提问作者Moussa Harajli

