如何从递归状态机配置中提取ACTION_键的联合类型?
从递归状态机配置中提取所有
ACTION_开头的键 问题背景
给定以下递归结构的TypeScript状态机配置,需要提取所有以ACTION_开头的键:
export const config = { initial: 'STATE_1', states: { STATE_1: { ACTION_5: 'STATE_2', initial: 'STATE_3', states: { STATE_3: { ACTION_1: 'STATE_4', ACTION_2: 'STATE_2', }, STATE_4: { ACTION_3: 'STATE_3', }, }, }, STATE_2: { ACTION_4: 'STATE_1', ACTION_5: 'STATE_3', initial: 'STATE_5', states: { STATE_5: { ACTION_6: 'STATE_6', }, STATE_6: { ACTION_6: 'STATE_5', }, }, }, }, };
尝试了如下类型实现,但推断结果为"STATE_1" | "STATE_2",不符合预期(期望结果是"ACTION_1" | "ACTION_2" | "ACTION_3" | "ACTION_4" | "ACTION_5" | "ACTION_6"):
type ActionUnion<T> = T extends { [K in keyof T]: infer U } ? U extends { states: any } ? ActionUnion<U['states']> // 递归处理嵌套states : U extends { [key: string]: any } ? keyof Omit<U, 'initial' | 'states'> // 提取ACTION键 : never : never;
需要正确的类型实现方案。
解决方案
可以通过递归遍历状态结构,结合键重映射筛选出目标键,具体实现如下:
正确的类型代码
// 提取单个状态节点中以ACTION_开头的键 type ExtractActionsFromState<S> = keyof { [K in keyof S as K extends `ACTION_${string}` ? K : never]: S[K] }; // 递归遍历所有状态节点,收集所有ACTION键 type ActionUnion<T> = T extends { states: infer S } ? ActionUnion<S> | ExtractActionsFromState<T> : T extends Record<string, infer State> ? ActionUnion<State> : ExtractActionsFromState<T>;
验证结果
使用上述类型验证:
type T1 = ActionUnion<typeof config>; // 推断结果:"ACTION_1" | "ACTION_2" | "ACTION_3" | "ACTION_4" | "ACTION_5" | "ACTION_6"
实现说明
ExtractActionsFromState:利用TypeScript的键重映射(as子句),仅保留以ACTION_开头的键,自动过滤initial、states等非目标字段;ActionUnion:递归处理多层嵌套结构:- 若当前类型包含
states字段,先递归处理states内部的子结构,同时提取当前节点的ACTION键; - 若当前是状态集合(如外层的
states对象),则递归遍历每个状态节点; - 最终提取所有层级的ACTION键并合并为联合类型。
- 若当前类型包含
内容的提问来源于stack exchange,提问作者Andy Jessop
相关产品推荐
相关产品推荐

