TypeScript中如何定义匹配数据字段类型的验证器集合类型?
解决方案
问题根因
报错的核心原因是
interface MyData extends Data继承了Record<string, string|number|Array<string>>的索引签名,导致TS判定MyData的所有字符串类型键对应的值都是string | number | string[]联合类型,生成Validators类型时,验证函数的入参被推导为该联合类型,和你实际声明的字段类型参数不兼容。
实现方案
有两种常用实现方式,可根据你的业务场景选择:
方案1:移除业务接口对索引签名类型的继承(推荐,覆盖绝大多数场景)
绝大多数情况下业务数据接口不需要额外的动态索引签名,直接将Data作为泛型约束使用即可:
// 定义公共类型约束,仅用于泛型校验,不需要业务接口继承 type DataConstraint = Record<string, string | number | Array<string>> // Validators泛型仅做类型约束 type Validators<T extends DataConstraint> = { [P in keyof T]?: (value: T[P]) => string } // 直接定义业务数据接口,不需要继承带索引签名的类型 interface MyData { first: string, second: number, third: Array<string>, } // 无报错,每个验证函数的入参都会自动匹配对应字段的类型 const validators: Validators<MyData> = { first: (value: string) => "", second: (value: number) => "", third: (value: string[]) => "" };
方案2:保留数据接口的动态索引签名
如果你确实需要业务数据对象支持动态添加任意符合类型的字段,可以在Validators类型中过滤掉索引签名,仅保留显式声明的字段校验:
type DataConstraint = Record<string, string | number | Array<string>> // 映射时过滤掉泛型的索引签名,仅保留显式定义的字段 type Validators<T extends DataConstraint> = { [P in keyof T as string extends P ? never : P]?: (value: T[P]) => string } // 继承带索引签名的约束,支持动态加字段 interface MyData extends DataConstraint { first: string, second: number, third: Array<string>, } const validators: Validators<MyData> = { first: (value: string) => "", // 入参正常识别为string类型,无报错 };
内容的提问来源于stack exchange,提问作者Grom
相关产品推荐
相关产品推荐

