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

如何从action creator对象生成actions联合类型?

从嵌套Action Creator对象生成Action联合类型的TypeScript实现

需要实现类型工具MakeActions,从嵌套的Action Creator对象中提取所有Action的联合类型,期望效果如下:

type SomeActionCreator = {
    hoge: () => {type: 'hoge'}
    foo: () => {type: 'foo'}
    baz: {
        baz1: () => {type: 'baz1'}
        baz2: () => {type: 'baz2'}
    }
}

type SomAction = MakeActions<SomeActionCreator>
// 期望结果:{type: 'hoge'} | {type: 'foo'} | {type: 'baz1'} | {type: 'baz2'} 

原实现及报错

原代码

type ActionCreator = (...args: never[]) => {type: string}
type ActionCreatorObj = {
    [name: string]: ActionCreator | ActionCreatorObj
}
type MakeActions<T extends ActionCreatorObj> = {
    [K in keyof T]: T[K] extends ActionCreator ? ReturnType<T[K]> : MakeActions<T[K]>
}[keyof T]

type SomeActionCreator = {
    hoge: () => {type: 'hoge'}
    foo: () => {type: 'foo'}
    baz: {
        baz1: () => {type: 'baz1'}
        baz2: () => {type: 'baz2'}
    }
}
type SomAction = MakeActions<SomeActionCreator>

报错信息

Type 'T[K]' does not satisfy the constraint 'ActionCreatorObj'.
  Type 'T[keyof T]' is not assignable to type 'ActionCreatorObj'.
    Type 'T[string] | T[number] | T[symbol]' is not assignable to type 'ActionCreatorObj'.
      Type 'T[string]' is not assignable to type 'ActionCreatorObj'.
        Type 'ActionCreator | ActionCreatorObj' is not assignable to type 'ActionCreatorObj'.
          Type 'ActionCreator' is not assignable to type 'ActionCreatorObj'.
            Index signature for type 'string' is missing in type 'ActionCreator'.(2344)

问题原因

报错核心是递归调用MakeActions<T[K]>时,TypeScript无法确定T[K]一定符合ActionCreatorObj约束——T[K]可能是ActionCreator函数类型,而函数类型不满足ActionCreatorObj的索引签名要求。

解决方案

去掉强约束,动态判断当前值是Action Creator函数还是嵌套对象,调整后的代码如下:

// 定义Action Creator类型:返回包含type属性的对象的函数
type ActionCreator = (...args: any[]) => { type: string };

// 递归提取Action联合类型
type MakeActions<T> = {
  [K in keyof T]: 
    // 如果是Action Creator函数,取其返回值
    T[K] extends ActionCreator 
      ? ReturnType<T[K]> 
      // 如果是嵌套对象,递归处理
      : T[K] extends object 
        ? MakeActions<T[K]> 
        // 非函数非对象的情况,返回never(目标场景不会触发)
        : never
}[keyof T];

// 测试用例
type SomeActionCreator = {
    hoge: () => {type: 'hoge'}
    foo: () => {type: 'foo'}
    baz: {
        baz1: () => {type: 'baz1'}
        baz2: () => {type: 'baz2'}
    }
}

type SomAction = MakeActions<SomeActionCreator>;
// SomAction 结果:{type: 'hoge'} | {type: 'foo'} | {type: 'baz1'} | {type: 'baz2'}

修改说明

  1. 移除ActionCreatorObj定义,避免强约束带来的类型不兼容;
  2. 在MakeActions中先判断T[K]是否为ActionCreator类型,若是则取返回值;
  3. 若不是函数则判断是否为对象类型,若是则递归处理嵌套结构;
  4. 通过[keyof T]将所有属性的类型展开为联合类型。

内容的提问来源于stack exchange,提问作者green

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.08 02:17:15