TypeScript中useReducer无法用对象属性作为switch case?
TypeScript useReducer中整合字符串常量到对象后类型推断异常问题
原可正常运行的写法
export const LOGIN_USER = "LOGIN_USER"; export const LOGOUT_USER = "LOGOUT_USER"; export type AuthActionType = LogInUser | LogOutUser; type LogInUser = { type: typeof LOGIN_USER; payload: User }; type LogOutUser = { type: typeof LOGOUT_USER }; export default function authReducer( state: AuthStateType, action: AuthActionType ) { switch (action.type) { case LOGIN_USER: { return { ...state, user: { username: action.payload.username, password: action.payload.password } }; } case LOGOUT_USER: { return { ...state, user: null }; } default: { return state; } } }
整合常量到对象后的异常写法
export const AUTH = { LOGIN_USER: "LOGIN_USER", LOGOUT_USER: "LOGOUT_USER" }; export type AuthActionType = LogInUser | LogOutUser; type LogInUser = { type: typeof AUTH.LOGIN_USER; payload: User }; type LogOutUser = { type: typeof AUTH.LOGOUT_USER }; export default function authReducer( state: AuthStateType, action: AuthActionType ) { switch (action.type) { case LOGIN_USER: { return { ...state, user: { username: action.payload.username, // 此处报错,无法正确推断类型 password: action.payload.password } }; } case LOGOUT_USER: { return { ...state, user: null }; } default: { return state; } } }
仅将类型定义从type: typeof LOGIN_USER改为type: typeof AUTH.LOGIN_USER,TypeScript就无法正常处理switch case的类型推断,这是为什么?
问题原因
TypeScript对单独声明的字符串常量和对象中字符串属性的类型推断逻辑存在差异:
- 单独声明的
export const LOGIN_USER = "LOGIN_USER"会被推断为字面量类型"LOGIN_USER",而非宽泛的string类型。这种精准的类型让TypeScript能在switch case中通过action.type精确收窄action的类型,从而正确识别action.payload的结构。 - 当把常量放入对象
AUTH后,TypeScript默认会将对象属性的类型推断为宽泛的string,而非具体的字面量值。此时typeof AUTH.LOGIN_USER的类型是string,而非"LOGIN_USER",导致switch case无法通过action.type区分不同的action类型分支,自然无法正确推断action.payload的存在和结构。
解决方法
给AUTH对象添加as const断言,强制TypeScript将对象属性的类型保留为字面量类型:
export const AUTH = { LOGIN_USER: "LOGIN_USER", LOGOUT_USER: "LOGOUT_USER" } as const;
同时修改switch case中的常量引用,使用对象内的属性:
switch (action.type) { case AUTH.LOGIN_USER: { return { ...state, user: { username: action.payload.username, password: action.payload.password } }; } case AUTH.LOGOUT_USER: { return { ...state, user: null }; } default: { return state; } }
内容的提问来源于stack exchange,提问作者Enfield Li
相关产品推荐
相关产品推荐

