如何在io-ts中对输入数据使用类型细化并派生无品牌输入类型
解决方案
1. 你使用branded类型的选择是完全正确的
branded类型是io-ts中为基础类型附加额外校验规则的标准实现,刚好匹配你的需求:既可以在运行时执行正则校验,又能在类型层面区分「已经过校验的合法版本号」和「普通字符串」,避免未校验的值流入后续业务逻辑。
2. 无需重复定义类型,直接使用io-ts内置InputOf工具类型即可获得无品牌的输入类型
io-ts的所有Codec都自带输入/输出两类类型描述:
TypeOf<Codec>是解码成功后的输出类型,也就是你现在用的带branded标记的安全类型InputOf<Codec>是Codec接受的输入类型,对于branded字符串来说,这个类型就是原生string,完全符合你的入参要求。
你只需要修改callFunction的入参类型即可,不需要新增任何自定义类型:
import { isRight } from 'fp-ts/Either'; import { brand, Branded, string, type, TypeOf, InputOf } from 'io-ts'; // 新增导入InputOf interface VersionBrand { readonly Version: unique symbol; } export const TypeVersion = brand( string, (value: string): value is Branded<string, VersionBrand> => /^\d+\.\d+\.\d+$/.test(value), 'Version' ); export const TypeMyStruct = type({ version: TypeVersion, }); export type Version = TypeOf<typeof TypeVersion>; export type MyStruct = TypeOf<typeof TypeMyStruct>; // 入参改用InputOf获取无品牌的输入类型 export function callFunction(data: InputOf<typeof TypeMyStruct>): boolean { const validation = TypeMyStruct.decode(data); // 校验通过后 validation.right 就是带branded标记的合法MyStruct类型,可直接用于后续安全逻辑 return isRight(validation); }
修改完成后,你就可以直接调用callFunction({ version: '1.2.3' }),编译不会报错,同时入参有完整的类型约束(只能传入version为字符串的对象,不会丢失类型信息变成any)。
如果你需要单独导出输入类型复用
可以直接基于InputOf定义,完全没有类型重复:
export type MyStructInput = InputOf<typeof TypeMyStruct> // 等价于 type MyStructInput = { version: string }
内容的提问来源于stack exchange,提问作者Carsten
相关产品推荐
相关产品推荐

