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

如何使用io-ts表示原生Enum类型?

使用io-ts解析TypeScript枚举

io-ts没有像zod的nativeEnum那样的官方内置方法,但可以通过手动实现Type实例或封装通用工具函数来支持枚举解析。以下是具体实现方案:

1. 手动实现针对特定枚举的Codec

以你的Fruit枚举为例,直接创建对应的io-ts类型:

import * as t from 'io-ts';
import { pipe } from 'fp-ts/lib/function';
import { chain } from 'fp-ts/lib/Either';

enum Fruit {
  Apple = 'apple',
  Orange = 'orange',
}

// 预存枚举的所有有效值,用于快速校验
const validFruitValues = new Set(Object.values(Fruit));

const FruitCodec = new t.Type<Fruit, Fruit, unknown>(
  'Fruit', // 类型名称,用于错误提示
  // 类型守卫:判断输入是否为有效Fruit枚举值
  (input): input is Fruit => typeof input === 'string' && validFruitValues.has(input as Fruit),
  // 验证逻辑:先校验是字符串,再校验是否在有效值集合中
  (input, context) => pipe(
    t.string.validate(input, context),
    chain(str => 
      validFruitValues.has(str as Fruit) 
        ? t.success(str as Fruit) 
        : t.failure(input, context, `无效的Fruit枚举值,必须是:${Array.from(validFruitValues).join(', ')}`)
    )
  ),
  // 编码逻辑:直接返回原值(枚举值本身就是字符串)
  t.identity
);

2. 封装通用工具函数(类似zod的nativeEnum)

如果需要复用枚举解析逻辑,可以封装一个通用函数,支持字符串和数字枚举:

import * as t from 'io-ts';
import { pipe } from 'fp-ts/lib/function';
import { chain } from 'fp-ts/lib/Either';

/**
 * 生成对应枚举的io-ts Codec
 * @param enumObj TypeScript枚举对象
 * @returns 可解析该枚举的io-ts Type实例
 */
function nativeEnum<T extends Record<string, string | number>>(enumObj: T): t.Type<T[keyof T], T[keyof T], unknown> {
  const enumValues = new Set(Object.values(enumObj));
  const enumName = enumObj.constructor.name;
  // 根据枚举值类型选择基础验证器(字符串/数字)
  const baseCodec = typeof enumObj[Object.keys(enumObj)[0]] === 'string' ? t.string : t.number;

  return new t.Type<T[keyof T], T[keyof T], unknown>(
    enumName,
    (input): input is T[keyof T] => enumValues.has(input as T[keyof T]),
    (input, context) => pipe(
      baseCodec.validate(input, context),
      chain(val => 
        enumValues.has(val) 
          ? t.success(val as T[keyof T]) 
          : t.failure(input, context, `无效的${enumName}枚举值,必须是:${Array.from(enumValues).join(', ')}`)
      )
    ),
    t.identity
  );
}

// 使用示例:直接传入枚举对象生成Codec
const FruitCodec = nativeEnum(Fruit);

测试验证

你可以通过以下代码验证Codec的效果:

// 有效输入
console.log(FruitCodec.decode('apple')); // 输出:right(Fruit.Apple)
console.log(FruitCodec.decode('orange')); // 输出:right(Fruit.Orange)

// 无效输入
console.log(FruitCodec.decode('banana')); // 输出:left(ValidationError),包含错误提示信息

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.16 06:05:08