TypeScript误将函数对象参数识别为string类型报错解决方法
问题背景
- 项目正从JavaScript逐步迁移至TypeScript,
checkRecordsExists函数所在文件必须保留JS格式,不能为适配TS修改该函数源码,否则会破坏其他依赖该函数的业务逻辑 - 该函数是定义在JS文件中的Express中间件,第二个参数为配置对象、默认值为空对象,支持
idName、paramLocation、optional、checkSource、additionalChecks、idDbField等可选配置项 - VSCode中TypeScript错误将该对象类型的参数推断为
string类型,在TS文件中调用checkRecordsExists(dbService.CustomPage, { checkSource: false })时,编译器抛出ts(2345)错误:类型'{ checkSource: boolean; }'的参数不能赋给类型'string'的参数 - 要求解决方案不能使用
//@ts-ignore类注释绕过类型检查
可行解决方案
方案1:新增独立类型声明文件(推荐,一劳永逸)
不需要改动原有JS文件,在JS文件的同级目录创建同名的.d.ts类型声明文件,手动补充函数的准确类型定义,TS会自动读取该声明文件做类型校验,完全不影响原有JS逻辑和其他JS文件的调用。
示例:假设原函数文件为./middleware/checkRecordsExists.js,则在同目录新建./middleware/checkRecordsExists.d.ts,写入以下内容:
import type { Request, RequestHandler } from 'express'; // 定义第二个参数的配置项类型 interface CheckRecordsExistsConfig { idName?: string; paramLocation?: 'body' | 'query' | 'params'; optional?: boolean; checkSource?: boolean; additionalChecks?: (req: Request) => boolean | Promise<boolean>; idDbField?: string; } // 声明函数的完整类型 declare function checkRecordsExists( dbModel: any, // 可替换为项目中实际的数据库模型类型,获得更精准的校验 config?: CheckRecordsExistsConfig ): RequestHandler; export default checkRecordsExists;
配置完成后,所有TS文件引入该中间件时都会自动获得正确的类型提示,传参错误时TS会正常抛出校验错误,不会再出现把配置对象识别成string的问题。
方案2:导入时指定函数类型(适合少量文件调用的场景)
如果不想新增全局类型声明文件,可以在调用该函数的TS文件中,导入时手动指定函数类型,类型定义仅对当前文件生效:
import type { Request, RequestHandler } from 'express'; import _checkRecordsExists from './middleware/checkRecordsExists.js'; // 定义配置项类型 interface CheckRecordsExistsConfig { idName?: string; paramLocation?: 'body' | 'query' | 'params'; optional?: boolean; checkSource?: boolean; additionalChecks?: (req: Request) => boolean | Promise<boolean>; idDbField?: string; } // 做类型转换,指定函数正确类型 const checkRecordsExists = _checkRecordsExists as ( dbModel: any, config?: CheckRecordsExistsConfig ) => RequestHandler; // 后续正常调用即可,不会触发ts(2345)错误 router.get( '/custom-page/detail', checkRecordsExists(dbService.CustomPage, { checkSource: false }), (req, res) => { res.json({ code: 0, data: req.record }) } );
注意:不要直接在传参位置用
as any之类的松散断言,会丢失配置项的类型校验能力,上述两种方案都可以保留完整的类型提示,配置项传错字段、传值类型不匹配时TS依然会正常报错。
内容的提问来源于stack exchange,提问作者Joel Adams
相关产品推荐
相关产品推荐

