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

TypeScript泛型含联合类型时z.infer类型推断异常问题

Zod泛型类型推断异常(联合类型场景)

问题场景

我正在开发一个工具,从用于表单验证的Zod Schema生成空/初始表单值(Schema字段必填,但初始值允许为空)。遇到的问题是:当泛型参数使用z.infer<S>而非具体Schema类型时,联合类型场景下的类型推断会出现异常,只有给传入的初始值添加as const才能恢复正确推断。

示例代码对比

错误写法(类型推断异常)

import { z } from "zod";

// 泛型参数直接使用z.infer<S>对应的结果类型T
function createInitialValue1<T>(schema: z.ZodType<T>, initial: Partial<T>) {
  return initial;
}

const roleSchema = z.object({
  role: z.union([z.literal("admin"), z.literal("user")])
});

// obj的类型被推断为Partial<{ role: string }>,丢失了联合字面量的精确类型
const obj = createInitialValue1(roleSchema, { role: "admin" });

正确写法(无需as const)

// 泛型参数约束为Zod Schema类型S,内部用z.infer<S>提取对应TypeScript类型
function createInitialValue2<S extends z.ZodType>(schema: S, initial: Partial<z.infer<S>>) {
  return initial;
}

// obj2的类型正确推断为Partial<{ role: "admin" | "user" }>
const obj2 = createInitialValue2(roleSchema, { role: "admin" });

问题原因

  1. 类型拓宽(Widening):当泛型参数直接使用z.infer<S>对应的T时,TypeScript会对传入的字面量值(比如"admin")自动执行类型拓宽,把窄字面量类型转为更宽泛的父类型(比如string)。对于联合字面量场景,这会导致"admin" | "user"被拓宽为string,丢失精确的联合类型信息。
  2. as const的作用:as const会强制TypeScript保留字面量的窄类型,阻止自动拓宽,所以能恢复正确推断,但显然不适合在所有场景添加。
  3. 泛型约束的差异:当泛型参数约束为S extends z.ZodType时,TypeScript会先推断出具体的Zod Schema类型(包含联合字面量的精确定义),再通过z.infer<S>从Schema中提取类型,这个过程不会触发字面量拓宽,因此能保留精确的联合类型。

解决方案

避免将z.infer<S>作为泛型参数直接使用,而是将泛型参数约束为Zod Schema类型(S extends z.ZodType),在函数参数或返回值中使用z.infer<S>来获取对应的TypeScript类型。这种写法既不需要额外添加as const,又能保证类型推断的准确性。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.24 12:33:19