如何在运行时检查联合类型中字符串字面量的有效性?
如何在运行时检查联合类型中字符串字面量的有效性?
看起来你遇到了TypeScript联合类型在运行时校验的典型问题——毕竟TypeScript的类型信息在编译后就被擦除了,没法直接用类型来做运行时验证。不过我们可以通过把编译时类型和运行时数据绑定的方式来解决这个问题,具体步骤如下:
首先,我们需要把联合类型里的action字面量提取成一个运行时可用的数组,这样既能用来做校验,又能保证和类型定义同步:
// 先定义运行时的合法action列表,用as const让TypeScript保留字面量类型 const validActions = ["run", "jump", "attack"] as const; // 从数组推导Action类型,这样类型和运行时值完全一致 type Action = typeof validActions[number]; // 基于Action类型定义你的Command(也可以直接沿用你原来的定义,这样更同步) type Command = { action: "run", x: number, y: number } | { action: "jump", height: number } | { action: "attack", weapon: "sword" | "knife" };
接下来,写一个简单的校验函数,判断某个字符串是否是合法的action,同时用类型谓词让TypeScript识别校验后的类型:
function isValidAction(action: string): action is Action { // 转成readonly string[]是为了适配includes的参数类型 return (validActions as readonly string[]).includes(action); }
如果需要校验整个Command对象(比如从API接收数据、处理用户输入时),可以写一个更完整的类型守卫函数,不仅检查action的合法性,还会验证对应action所需的属性:
function isCommand(obj: unknown): obj is Command { // 先排除非对象的情况 if (typeof obj !== "object" || obj === null) { return false; } // 提取action属性,先做基础检查 const { action } = obj as { action?: string }; if (!action || !isValidAction(action)) { return false; } // 根据不同的action,校验对应的必填属性 switch (action) { case "run": return typeof (obj as { x?: number }).x === "number" && typeof (obj as { y?: number }).y === "number"; case "jump": return typeof (obj as { height?: number }).height === "number"; case "attack": const { weapon } = obj as { weapon?: string }; return weapon === "sword" || weapon === "knife"; default: // 因为isValidAction已经过滤了非法action,这里理论上不会执行到 return false; } }
使用的时候,只要通过isCommand的校验,TypeScript就会自动把对象推断为Command类型,同时运行时也确保了数据的合法性:
// 示例:处理一个未知的输入 const input = JSON.parse('{"action": "run", "x": 10, "y": 20}'); if (isCommand(input)) { // 这里input会被推断为Command类型,可以安全访问对应的属性 console.log(input.x, input.y); } else { console.log("非法的Command格式"); }
这种方法的好处是,后续如果要添加新的action,只需要在validActions数组里添加新值,同时更新Command类型定义,就能保证运行时校验和编译时类型的一致性,不会出现漏校验或者类型不匹配的问题。
内容来源于stack exchange
相关产品推荐
相关产品推荐

