React TypeScript中间件paramsSerializer处TypeScript类型错误求助
解决React TypeScript项目中API中间件的类型错误
问题背景
我正在开发一个React TypeScript项目,已编写API中间件用于将后端返回数据的键转换为驼峰式(camelCase),将发送至后端数据的键转换为蛇形命名(snakeCase),使用js-convert-case包处理键名转换。中间件代码如下:
import Axios from 'axios' import * as queryString from 'query-string' import * as jsConvert from 'js-convert-case' import { cleanParams } from '_utilities/common' import { REQUEST_TYPES } from './constants' import { useLoginUser } from '_store/user' interface IAuth { method?: string url?: string data?: any params?: any contentType?: string isTransformRequestRequired?: boolean isAuthroizedToken?: boolean } export function apiCaller({ method = REQUEST_TYPES.GET, url = '', params = {}, data = {}, contentType = 'application/json', isAuthroizedToken = true, isTransformRequestRequired = true, }: IAuth) { const user = useLoginUser.getState().user const setLogout = useLoginUser.getState().setLogout const token = user?.data?.token || '' let headers if (isAuthroizedToken) { headers = { Authorization: `Token ${token}`, 'Content-Type': contentType, } } else { headers = { 'Content-Type': contentType, } } return Axios({ method, url, params, paramsSerializer: (queryParams) => queryString.stringify(jsConvert.snakeKeys(cleanParams(queryParams))), data, transformRequest: [ (reqData) => isTransformRequestRequired ? JSON.stringify(jsConvert.toSnakeCase(reqData)) : reqData, ], transformResponse: [ (respData) => { if (typeof respData === 'string') return jsConvert.camelKeys(JSON.parse(respData), { recursive: true, recursiveInArray: true, }) else { return jsConvert.camelKeys(respData, { recursive: true, recursiveInArray: true }) } }, ], headers: headers, responseType: 'json', validateStatus: (status) => status >= 200 && status < 300, }) .then(({ data: resp }) => resp) .catch((error) => { if (error?.response?.status === 401) { setLogout() } else { throw error } }) }
类型错误详情
在以下代码段出现TypeScript类型错误:
paramsSerializer: (queryParams) => queryString.stringify(jsConvert.snakeKeys(cleanParams(queryParams))),
错误提示:
Argument of type 'object | null' is not assignable to parameter of type 'Record<string, any>'. Type 'null' is not assignable to type 'Record<string, any>'.ts(2345) (alias) snakeKeys(obj: any, opt?: Options | undefined): object | null export snakeKeys
cleanParams函数代码
export const cleanParams = (obj: Record<string, any>): Record<string, any> => { Object.keys(obj).forEach((key) => { if (obj[key] === false) { delete obj[key] } else if (obj[key]) { if (key === 'isDisabled') { delete obj[key] obj.enabled = false } } }) Object.keys(obj).forEach((key) => { if ( obj[key] === null || obj[key] === '' || obj[key] === undefined || obj[key].length === 0 || (key === 'status' && obj[key] === 0) ) { delete obj[key] } }) Object.keys(obj).forEach((key) => { if (obj[key] === true) { obj[key] = 1 } }) return obj }
解决方案
问题核心是jsConvert.snakeKeys的类型定义标注返回值为object | null,而queryString.stringify要求传入Record<string, any>类型。即便cleanParams返回的是确定的Record<string, any>,TypeScript仍会遵循snakeKeys的类型声明报错,以下是几种解决方式:
方式1:类型断言
直接通过类型断言告诉TypeScript,snakeKeys的返回值不会为null:
paramsSerializer: (queryParams) => queryString.stringify(jsConvert.snakeKeys(cleanParams(queryParams)) as Record<string, any>),
方式2:空值兜底处理
显式处理snakeKeys可能返回null的情况(实际业务中不会触发),用空对象兜底:
paramsSerializer: (queryParams) => { const convertedParams = jsConvert.snakeKeys(cleanParams(queryParams)); return queryString.stringify(convertedParams ?? {}); },
方式3:自定义类型声明(可选)
如果确定snakeKeys在传入非null对象时绝不会返回null,可以创建类型声明文件覆盖原有定义:
在项目中创建src/types/js-convert-case.d.ts,内容如下:
import 'js-convert-case'; declare module 'js-convert-case' { export function snakeKeys(obj: Record<string, any>, opt?: Options): Record<string, any>; }
内容的提问来源于stack exchange,提问作者Asad Ur Rehman
相关产品推荐
相关产品推荐

