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
相关产品推荐
相关产品推荐

