如何使用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
相关产品推荐
相关产品推荐

