英文:
Build union of keys in recursive object with specific shape
问题
以下是翻译好的代码部分:
type ActionUnion<T> = T extends { [K in keyof T]: infer U }
? U extends { states: any }
? ActionUnion<U['states']> // 递归调用用于嵌套状态
: U extends { [key: string]: any }
? keyof Omit<U, 'initial' | 'states'> // 提取动作键
: never
: never;
type T1 = ActionUnion<typeof config>; // 应该是 "ACTION_1" | "ACTION_2" | 等等...
请注意,我已经移除了 HTML 实体编码(如 <
和 "
)以获得更清晰的代码。
英文:
I'm trying to extract the ACTION_
keys from the following config shape (it's a state machine). Notice that a state can have initial
, states
, then any number of actions:
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',
},
},
},
},
};
The best I can come up with at the moment is this:
type ActionUnion<T> = T extends { [K in keyof T]: infer U }
? U extends { states: any }
? ActionUnion<U['states']> // recursive call for nested states
: U extends { [key: string]: any }
? keyof Omit<U, 'initial' | 'states'> // extract action keys
: never
: never;
But this is inferred as "STATE_1" | "STATE_2"
.
type T1 = ActionUnion<typeof config>; // should be "ACTION_1" | "ACTION_2" | etc...
I think I'm probably making this more complex than it needs to be.
答案1
得分: 0
以下是代码部分的中文翻译:
// 工具函数:
// `Prettify` - 简化IDE显示的类型:
type Prettify<T> = T extends infer R ? { [K in keyof R]: R[K] } : never;
// 接下来,使用[映射类型](https://www.typescriptlang.org/docs/handbook/2/mapped-types.html)遍历对象并检查其键是否以`ACTION_`开头,如果是,则选择该键,否则,如果属性是对象,则以相同的方式递归检查该属性的键,如果前述条件都不成立,则分配为`never`。然后,提取该对象的值以获得值的并集:
type ActionUnion<T extends object> = Prettify<{
[K in keyof T]: K extends `ACTION_${string}`
? K
: T[K] extends object
? ActionUnion<T[K]>
: never;
}[keyof T]>;
// 用法示例:
// 类型 Actions = "ACTION_4" | "ACTION_5" | "ACTION_6" | "ACTION_3" | "ACTION_1" | "ACTION_2"
type Actions = ActionUnion<typeof config>;
您可以在playground中测试此代码。
请注意,我只翻译了代码部分,不包括代码之外的内容。
英文:
Utilities:
Prettify
- simplifies the type shown by the IDE:
type Prettify<T> = T extends infer R ? { [K in keyof R]: R[K] } : never;
Next, using the mapped types we will map through the object and check if the key of it starts with ACTION_
then we pick the key, otherwise if the property is an object, we recursively check in the same manner the keys of that property, if none of the previous conditions are true, we just assign never
. Then we extract the values of that object to get the union of values:
type ActionUnion<T extends object> = Prettify<
{
[K in keyof T]: K extends `ACTION_${string}`
? K
: T[K] extends object
? ActionUnion<T[K]>
: never;
}[keyof T]
>;
Usage:
// type Actions = "ACTION_4" | "ACTION_5" | "ACTION_6" | "ACTION_3" | "ACTION_1" | "ACTION_2"
type Actions = ActionUnion<typeof config>;
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论