MongoDB 4.1.4结合TypeScript使用findOne方法出现类型不匹配错误:Type ‘void’ is not assignable to type ‘DBUser | undefined’.ts(2322)
这问题我之前碰到过!根源在于TypeScript的类型推断误将你的findOne调用匹配到了带回调函数的重载版本(返回void),而非我们需要的异步Promise版本。
为什么会出现这个错误?
MongoDB Node.js驱动的findOne有多个重载:
- 一个是传入回调函数的版本:
findOne(callback: Callback<Document | null>): void,这就是VSCode提示的那个重载 - 另一个是无回调的异步版本:
findOne(filter: Filter<T>): Promise<T | null>
之所以会匹配错误,大概率是你的collection变量没有正确指定泛型类型,默认是Collection<Document>,导致TypeScript无法准确推断你要调用的是Promise版本,反而优先匹配了回调重载(哪怕你没传回调,旧版本驱动的类型定义可能存在重载顺序或推断逻辑的问题)。
修复步骤
1. 明确指定Collection的泛型类型
确保你的collection被声明为Collection<DBUser>,而不是默认的Collection<Document>:
import { Collection, Filter } from 'mongodb'; // 假设你的DBUser接口是这样的 interface DBUser { apiKey: string; // 其他用户字段... } // 创建/获取集合时指定泛型 const collection: Collection<DBUser> = db.collection<DBUser>('users');
这一步是关键,让TypeScript知道集合操作的文档类型是DBUser,从而正确识别findOne的返回类型为Promise<DBUser | null>。
2. 对齐返回类型(可选但推荐)
注意MongoDB驱动的findOne返回的是Promise<T | null>(找不到文档时返回null),而你的函数声明返回DBUser | undefined。为了类型严谨,你可以:
- 要么修改函数返回类型为
Promise<DBUser | null>:
async function getUser(): Promise<DBUser | null> { const filter: Filter<DBUser> = { apiKey: '123' }; return collection.findOne(filter); }
- 要么将
null转换为undefined,保持原返回类型:
async function getUser(): Promise<DBUser | undefined> { const filter: Filter<DBUser> = { apiKey: '123' }; const user = await collection.findOne(filter); return user ?? undefined; // 使用空值合并运算符转换null为undefined }
3. 强制指定重载(极端情况备用)
如果上述方法仍不生效,可以通过类型断言强制指定使用Promise版本的重载:
async function getUser(): Promise<DBUser | undefined> { const filter: Filter<DBUser> = { apiKey: '123' }; return (collection.findOne as (filter: Filter<DBUser>) => Promise<DBUser | null>)(filter) .then(user => user ?? undefined); }
不过这是兜底方案,优先推荐前两种方法。
总结
核心问题是集合的泛型类型未正确指定,导致TypeScript匹配了错误的findOne重载。只要明确Collection<DBUser>的类型,再对齐返回值的类型定义,就能解决这个奇怪的类型错误。
内容的提问来源于stack exchange,提问作者bella balola

