使用MongoDB的.countDocuments方法时遇到类型错误
Hey there, let's break down why you're hitting this TypeScript error and how to fix it.
The core issue here is that your generic type T only extends Mongoose's Document interface, but TypeScript can't confirm that every possible T will have a createdAt field. Since your filter relies on createdAt, TypeScript throws an error because it can't guarantee that property exists on all models you might pass to this function.
Fix: Add a Type Constraint to Ensure createdAt Exists
The cleanest way to resolve this is to enforce that any model passed to this function must include a createdAt field. Here's how to do it:
First, define an interface that requires the createdAt property:
interface HasCreatedAt { createdAt: Date; }
Then update your function's generic type to extend both Document and this new interface:
import { Document, Model, FilterQuery } from "mongoose"; interface MonthData { month: string; count: number; }; interface HasCreatedAt { createdAt: Date; } export async function generateLast12MonthsData<T extends Document & HasCreatedAt>( model: Model<T> ): Promise<{last12Months:MonthData[]}> { const last12Months: MonthData[] = []; const currentDate = new Date(); currentDate.setDate(currentDate.getDate() + 1); for(let i=11; i>=0; i--){ const endDate = new Date( currentDate.getFullYear(), currentDate.getMonth(), currentDate.getDate() - i * 28 ); const startDate = new Date( endDate.getFullYear(), endDate.getMonth(), endDate.getDate() - 28 ); const monthYear = endDate.toLocaleString( 'default', { day: "numeric", month: "short", year: "numeric", } ); const count = await model.countDocuments( { createdAt: { $gte: startDate, $lt: endDate, }, } ); last12Months.push( { month: monthYear, count, } ) } return { last12Months }; }
This tells TypeScript that any model passed to generateLast12MonthsData must have a createdAt field of type Date, making your filter valid and eliminating the error.
Alternative (Less Safe) Approach: Type Assertion
If for some reason you can't add the type constraint (though this isn't recommended for type safety), you could use a type assertion to bypass the error:
const count = await model.countDocuments( { createdAt: { $gte: startDate, $lt: endDate, }, } as FilterQuery<T> );
This works but skips TypeScript's checks, so you risk passing a model without createdAt which would cause runtime issues. Stick with the first solution for better safety.
备注:内容来源于stack exchange,提问作者Minh Dương Nguyễn

