如何在TypeScript中实现Reducer对联合类型Action的类型收窄?
如何用TypeScript实现Reducer中Action类型的自动识别?
你需要处理两种不同类型的Action,并且希望TypeScript能在判断后自动识别对应的属性,其实核心是利用TypeScript的**判别式联合类型(Discriminated Unions)**特性,加上类型缩小逻辑来实现。下面是具体的实现步骤:
1. 先明确Action的类型定义
首先把两种Action类型和它们的联合类型定义好,注意每个Action都要有一个唯一的type字面量属性,这是TypeScript能自动识别类型的关键:
// 处理todo项的Action interface ItemAction { type: 'ADD_TODO' | 'DELETE_TODO' | 'TOGGLE_TODO'; id: number; } // 处理搜索查询的Action interface QueryAction { type: 'SET_QUERY'; query: string; } // 合并成联合类型,作为Reducer的Action参数类型 type AppAction = ItemAction | QueryAction;
2. 实现Reducer中的类型自动识别
有两种常用的方式来实现你想要的逻辑:
方式一:直接通过type属性做分支判断
因为每个Action的type是字面量类型,TypeScript会自动根据type的值缩小变量的类型范围:
function todoReducer(state: any, action: AppAction) { if (action.type === 'ADD_TODO' || action.type === 'DELETE_TODO' || action.type === 'TOGGLE_TODO') { // 这里TypeScript会自动识别action为ItemAction,id属性可以直接访问 console.log(action.id); } else { // 剩下的只有SET_QUERY类型,TypeScript自动识别为QueryAction,query属性可用 console.log(action.query); } }
如果用switch语句会更清晰,尤其当Action类型较多时:
function todoReducer(state: any, action: AppAction) { switch (action.type) { case 'ADD_TODO': case 'DELETE_TODO': case 'TOGGLE_TODO': // 这里action被自动缩小为ItemAction console.log(action.id); break; case 'SET_QUERY': // 这里action被自动缩小为QueryAction console.log(action.query); break; default: // 处理未知类型,避免遗漏 throw new Error(`Unknown action type: ${action.type}`); } }
方式二:自定义类型守卫函数
如果觉得多个type判断太繁琐,可以写一个自定义类型守卫函数,把判断逻辑封装起来:
// 自定义类型守卫,返回值`action is ItemAction`告诉TypeScript:如果函数返回true,action就是ItemAction类型 function isItemAction(action: AppAction): action is ItemAction { return ['ADD_TODO', 'DELETE_TODO', 'TOGGLE_TODO'].includes(action.type); } function todoReducer(state: any, action: AppAction) { if (isItemAction(action)) { // TypeScript自动识别为ItemAction,id属性可用 console.log(action.id); } else { // 自动识别为QueryAction,query属性可用 console.log(action.query); } }
原理说明
这里的核心是判别式联合类型:当多个接口有一个共同的属性(这里是type),且该属性的值是字面量类型时,TypeScript可以通过这个属性的值来精确判断变量的具体类型,从而实现类型自动缩小,不需要手动用as做类型断言。
内容的提问来源于stack exchange,提问作者vasily
相关产品推荐
相关产品推荐

