TypeScript动态条件类型问题:数组枚举的Schema类型定义异常
问题解决:基于TypeScript类型生成Schema的枚举类型适配
核心问题分析
- 原
Enum<T> = T仅为类型别名,TypeScript无法区分普通联合类型与自定义枚举类型,导致TypeOf<T>错误将枚举识别为string。 EnumSchema<T>的enums字段定义为T[],当T是联合类型时,TypeScript要求数组每个元素必须匹配整个联合类型,而非单个成员。- 原
User的status本质仍是普通联合类型,赋值非法值不会触发校验错误。
修正后的完整代码
// 用品牌类型标记枚举,让TypeScript区分普通类型与自定义枚举 type Enum<T> = T & { __brand: 'Enum' }; // 辅助函数:自动生成带品牌标记的枚举数组 const createEnum = <T extends string | number>(values: T[]) => values as Enum<T>[]; // 转换TypeScript类型为Schema的type字符串 type TypeOf<T> = T extends object ? 'object' : T extends { __brand: 'Enum' } ? 'enum' : 'string'; // 动态Schema定义 type Schema<T> = T extends object ? ObjectSchema<T> : T extends { __brand: 'Enum' } ? EnumSchema<T> : BaseSchema<T>; type BaseSchema<T> = { type: TypeOf<T>; default?: T; } type ObjectSchema<T> = BaseSchema<T> & { fields: { [K in keyof T]?: Schema<T[K]> }; } // 修正enums类型为readonly T[],支持联合类型成员数组 type EnumSchema<T> = BaseSchema<T> & { enums: readonly T[]; } // ------------------------------ // 使用示例 // ------------------------------ // 定义枚举值 const UserStatus = createEnum(['verified', 'created']); // 提取带品牌标记的枚举类型 type UserStatusType = typeof UserStatus[number]; // 创建User类型 type User = { name: string; status: UserStatusType; } // 创建User Schema const userSchema: Schema<User> = { type: 'object', fields: { name: { type: 'string', default: 'John', }, status: { type: 'enum', // 不再报错 enums: UserStatus, // 不再报错 default: 'created' } } } // 创建User对象 const user: User = { name: 'Smith', status: 'test', // 触发预期错误:类型"test"不能赋值给类型"Enum<'verified' | 'created'>" }
关键修改说明
- 品牌类型标记枚举:给
Enum<T>添加__brand: 'Enum'属性,让TypeScript将其视为独立于普通T的类型,确保TypeOf<T>能准确识别枚举并返回'enum'。 - 辅助函数简化枚举创建:
createEnum自动生成带品牌标记的枚举数组,避免手动编写品牌类型的繁琐操作。 - 修正枚举数组类型:将
enums: T[]改为enums: readonly T[],TypeScript会允许数组包含联合类型的单个成员,解决数组元素类型不匹配问题。 - 严格限制枚举类型:通过
typeof UserStatus[number]提取带品牌标记的枚举类型,确保赋值非法值时触发TypeScript校验错误。
内容的提问来源于stack exchange,提问作者Nanang Mahdaen El-Agung
相关产品推荐
相关产品推荐

