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

TypeScript:Zod Schema验证下泛型函数返回类型推断异常

解决Zod Schema验证中函数返回类型推断为any的问题

你的问题核心在于原函数的泛型推导逻辑存在缺陷:selectFormFactorDevice的泛型T依赖FormFactorDevice<T>的返回类型,但TypeScript无法从传入的formFactorDevice反向推导出T,最终导致z.infer<T>被推断为any。

修改方案一:直接定义字段类型结构

先抽离FormFactorDevice的类型结构,让函数泛型直接对应字段的实际类型,TypeScript就能自动完成推导:

import { z } from 'zod';

export const FormFactorDevice = <T extends z.ZodTypeAny>(fieldSchema: T) =>
  z.object({
    all: z.optional(fieldSchema),
    phone: z.optional(fieldSchema),
    smalltablet: z.optional(fieldSchema),
    tablet: z.optional(fieldSchema),
    laptop: z.optional(fieldSchema),
    desktop: z.optional(fieldSchema),
  });

export const FormFactor = <Z extends z.ZodTypeAny>(fieldSchema: Z) =>
  z.object({
    isFormFactor: z.literal(true).default(true),
    all: z.optional(fieldSchema),
    landscape: z.optional(FormFactorDevice(fieldSchema)),
    portrait: z.optional(FormFactorDevice(fieldSchema)),
  });

// 抽离FormFactorDevice的类型结构
type FormFactorDeviceStructure<T> = {
  all?: T;
  phone?: T;
  smalltablet?: T;
  tablet?: T;
  laptop?: T;
  desktop?: T;
};

export const selectFormFactorDevice = <T>(
  formFactorDevice: FormFactorDeviceStructure<T>,
  deviceType: keyof FormFactorDeviceStructure<T>
): T | undefined => {
  return formFactorDevice[deviceType];
};

// 测试
const b = FormFactorDevice(z.string()).parse({
  all: '100',
  smalltablet: '200',
  phone: '300',
});

const d = selectFormFactorDevice(b, 'all'); // 类型自动推断为 string | undefined

修改方案二:基于Zod推断类型调整泛型

如果不想额外定义类型结构,可以让泛型参数直接对应FormFactorDevice的推断类型,再从中提取字段类型:

import { z } from 'zod';

// 保留原有的FormFactorDevice和FormFactor定义
export const FormFactorDevice = <T extends z.ZodTypeAny>(fieldSchema: T) =>
  z.object({
    all: z.optional(fieldSchema),
    phone: z.optional(fieldSchema),
    smalltablet: z.optional(fieldSchema),
    tablet: z.optional(fieldSchema),
    laptop: z.optional(fieldSchema),
    desktop: z.optional(fieldSchema),
  });

export const FormFactor = <Z extends z.ZodTypeAny>(fieldSchema: Z) =>
  z.object({
    isFormFactor: z.literal(true).default(true),
    all: z.optional(fieldSchema),
    landscape: z.optional(FormFactorDevice(fieldSchema)),
    portrait: z.optional(FormFactorDevice(fieldSchema)),
  });

export const selectFormFactorDevice = <FFD extends z.infer<ReturnType<typeof FormFactorDevice<any>>>>(
  formFactorDevice: FFD,
  deviceType: keyof FFD
): FFD[keyof FFD] => {
  return formFactorDevice[deviceType];
};

// 测试
const b = FormFactorDevice(z.string()).parse({
  all: '100',
  smalltablet: '200',
  phone: '300',
});

const d = selectFormFactorDevice(b, 'all'); // 类型自动推断为 string | undefined

两种方案都能让函数自动推断出正确的返回类型,无需手动指定泛型参数。

内容的提问来源于stack exchange,提问作者Viet Hoang Do

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.24 15:02:33