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

如何在TypeScript中实现类似z.infer<>的泛型获取器

实现类似Zod的z.infer<>/z.input<>/z.output<>工具类型

Zod这类工具类型的核心逻辑是:让每个Schema类内置类型元数据,再通过TypeScript的索引类型提取这些元数据。下面一步步拆解实现思路:

1. 核心基础:带类型标记的Schema类

所有Zod Schema的父类都会定义内部类型成员(比如_inferType),用来存储当前Schema对应的TS类型。先实现一个最简版的基类约定:

// 基础Schema接口,约定所有Schema必须包含的类型标记
interface Schema<TInfer = unknown, TInput = TInfer, TOutput = TInfer> {
  // 存储最终推断出的类型
  _inferType: TInfer;
  // 存储输入接受的类型(比如coerce类型的input是原始类型,output是转换后的类型)
  _inputType: TInput;
  // 存储输出的类型
  _outputType: TOutput;
}

// 字符串Schema实现
class StringSchema implements Schema<string> {
  _inferType!: string;
  _inputType!: string;
  _outputType!: string;

  // 模拟Zod的链式方法,比如optional()
  optional() {
    return new OptionalSchema(this) as Schema<string | undefined>;
  }
}

// 可选类型Schema实现
class OptionalSchema<T extends Schema> implements Schema<
  T['_inferType'] | undefined,
  T['_inputType'] | undefined,
  T['_outputType'] | undefined
> {
  _inferType!: T['_inferType'] | undefined;
  _inputType!: T['_inputType'] | undefined;
  _outputType!: T['_outputType'] | undefined;

  constructor(private schema: T) {}
}

2. 实现工具类型:提取元数据

通过索引类型查询,直接提取Schema实例类型中的内部标记,就能实现和Zod一致的工具类型:

// 对应z.infer<>
type Infer<T extends Schema> = T['_inferType'];

// 对应z.input<>
type Input<T extends Schema> = T['_inputType'];

// 对应z.output<>
type Output<T extends Schema> = T['_outputType'];

3. 验证效果

测试一下这些工具类型的实际作用:

const stringSchema = new StringSchema();
type StringType = Infer<typeof stringSchema>; // 类型为string

const optionalStringSchema = stringSchema.optional();
type OptionalStringType = Infer<typeof optionalStringSchema>; // 类型为string | undefined

4. 进阶:处理带转换的Schema(比如coerce)

Zod的input和output主要区别体现在带转换的场景,比如z.coerce.number()的输入可以是字符串/布尔值,输出是数字。我们来实现这个场景:

class CoerceNumberSchema implements Schema<number, string | number | boolean, number> {
  _inferType!: number;
  // 输入支持字符串、数字、布尔值
  _inputType!: string | number | boolean;
  // 输出是转换后的数字
  _outputType!: number;
}

const coerceNumber = new CoerceNumberSchema();
type CoerceNumberInput = Input<typeof coerceNumber>; // string | number | boolean
type CoerceNumberOutput = Output<typeof coerceNumber>; // number

关键原理总结

  • 每个Schema类必须显式声明_inferType/_inputType/_outputType三个类型成员,用来存储对应TS类型
  • 工具类型本质是索引类型查询,直接提取Schema实例类型中的内部标记
  • 链式方法(比如optional()、coerce)会返回新的Schema类,其内部类型成员基于原Schema的类型修改

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.14 04:15:40