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

TypeScript动态条件类型问题:数组枚举的Schema类型定义异常

问题解决:基于TypeScript类型生成Schema的枚举类型适配

核心问题分析

  1. 原Enum<T> = T仅为类型别名,TypeScript无法区分普通联合类型与自定义枚举类型,导致TypeOf<T>错误将枚举识别为string。
  2. EnumSchema<T>的enums字段定义为T[],当T是联合类型时,TypeScript要求数组每个元素必须匹配整个联合类型,而非单个成员。
  3. 原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'>"
}

关键修改说明

  1. 品牌类型标记枚举:给Enum<T>添加__brand: 'Enum'属性,让TypeScript将其视为独立于普通T的类型,确保TypeOf<T>能准确识别枚举并返回'enum'。
  2. 辅助函数简化枚举创建:createEnum自动生成带品牌标记的枚举数组,避免手动编写品牌类型的繁琐操作。
  3. 修正枚举数组类型:将enums: T[]改为enums: readonly T[],TypeScript会允许数组包含联合类型的单个成员,解决数组元素类型不匹配问题。
  4. 严格限制枚举类型:通过typeof UserStatus[number]提取带品牌标记的枚举类型,确保赋值非法值时触发TypeScript校验错误。

内容的提问来源于stack exchange,提问作者Nanang Mahdaen El-Agung

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.19 15:35:29