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

TypeScript 联合类型场景下如何实现通用Action构造回调函数?

问题根源

你当前的实现没有将入参的ActionTypes枚举值和对应的GameAction子类型做类型绑定,TypeScript无法根据你传入的type值自动匹配对应的payload类型,也无法区分哪些action不需要payload参数。你定义的PayloadGameAction['payload']会直接取所有带payload的动作的载荷类型联合(即boolean | GameInfoPayload),无论你传什么type,返回的回调都要求传入这个联合类型,自然会出现类型不匹配的错误。

解决方案

给buildAction添加泛型约束,关联入参type和对应的动作类型、载荷类型:

enum ActionTypes {
    CREATE_GAME = 'CREATE_GAME',
    GET_GAME_INFO = 'GET_GAME_INFO',
    PARTICIPANT_JOIN = 'PARTICIPANT_JOIN',
}

interface CreateGame {
    type: ActionTypes.CREATE_GAME;
}

interface GameInfoPayload {
    gameid: number,
    participants: [],
    phase: string,
    activated: boolean
}

interface GetGameInfo {
    type: ActionTypes.GET_GAME_INFO;
    payload: GameInfoPayload;
}

interface ParticipantJoin {
    type: ActionTypes.PARTICIPANT_JOIN;
    payload: boolean;
}

type GameAction = CreateGame |
                  GetGameInfo |
                  ParticipantJoin;

// 新增工具类型:根据Action类型枚举值,匹配对应的完整Action结构
type ActionByType<T extends ActionTypes> = Extract<GameAction, { type: T }>
// 新增工具类型:根据Action类型枚举值,匹配对应的payload类型,无payload则返回never
type ActionPayload<T extends ActionTypes> = ActionByType<T> extends { payload: infer P } ? P : never;

const buildAction = <T extends ActionTypes>(type: T) => {
    // 判断当前类型是否需要payload
    type NeedPayload = ActionByType<T> extends { payload: unknown } ? true : false;
    // 按需定义回调的参数规则
    return (payload: NeedPayload extends true ? ActionPayload<T> : void = undefined as any): GameAction => {
        if (payload === undefined) {
            return { type } as GameAction;
        }
        return { type, payload } as GameAction;
    }
}

// 测试用例,类型校验完全正常
const createGame = buildAction(ActionTypes.CREATE_GAME);
createGame(); // 无payload,不需要传参

const getGameInfo = buildAction(ActionTypes.GET_GAME_INFO);
getGameInfo({ gameid: 1, participants: [], phase: 'init', activated: false }); // 必须传入符合格式的GameInfoPayload

const participantJoin = buildAction(ActionTypes.PARTICIPANT_JOIN);
participantJoin(true); // 必须传入布尔值

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.02 03:48:05