You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何为MongoDB find().toArray()返回值定义正确的TypeScript类型?

解决MongoDB查询结果的TypeScript类型错误问题

问题背景

以下是从MongoDB获取数据的函数定义:

export const getPopulatedCountriesByCountryIdsDB = async (countryIds: any[]) => {
    try {
        const query = {
            id: {$in: countryIds}
        }
        const db = await getDb();
        const collectionName = process.env.MONGO_DB_COLLECTION_POPULATED_COUNTRY!;
        const countries = await db?.collection(collectionName).find<Country>(query).toArray();
        return countries;
    } catch (err) {
        logger.error('Error in getPopulatedCountriesByCountryIdsDB:', err);
    }
}

对应的Country接口定义:

export interface Country {
    id: ObjectId;
    cities: []
};

调用函数后尝试访问嵌套属性时:

const countries = await getPopulatedCountriesByCountryIdsDB(countriesIds!);
const country = countries!.filter((country: any) => country.id === countryId);
const cities = country.cities.filter((city: any) => city.id === cityId);

出现错误:

Property 'cities' does not exist on type 'Country[]'

更新Country接口为cities: any[]后,仍出现相同错误;若不为find方法传入类型参数,会出现:

Property 'cities' does not exist on type 'WithId[]'.

错误原因分析

  1. 核心问题:filter返回数组而非单个对象
    Array.filter()方法的返回值始终是一个数组(即使只匹配到一个元素),所以country的类型是Country[],而非单个Country对象,自然无法直接访问cities属性。

  2. 类型定义不完善

    • 原Country接口中cities: []是固定长度的空数组类型,无法匹配实际包含城市数据的数组;
    • 函数未明确返回类型,TypeScript无法准确推断返回值的结构;
    • 未定义City接口,导致只能用any类型,失去TypeScript的类型校验能力。

解决方案

1. 完善类型定义

先定义City接口,再修正Country接口:

import { ObjectId } from "mongodb";

export interface City {
    id: ObjectId;
    // 可补充城市的其他属性,比如name、population等
}

export interface Country {
    id: ObjectId;
    cities: City[];
}

2. 明确函数返回类型

为数据库查询函数添加明确的返回类型,避免TypeScript推断模糊:

import { ObjectId, Db } from "mongodb";

// 假设getDb的返回类型是Promise<Db | undefined>
export const getPopulatedCountriesByCountryIdsDB = async (countryIds: ObjectId[]): Promise<Country[] | undefined> => {
    try {
        const query = {
            id: {$in: countryIds}
        }
        const db = await getDb();
        if (!db) return undefined; // 提前处理db为空的情况
        const collectionName = process.env.MONGO_DB_COLLECTION_POPULATED_COUNTRY!;
        // 明确集合的类型为Country
        const countries = await db.collection<Country>(collectionName).find(query).toArray();
        return countries;
    } catch (err) {
        logger.error('Error in getPopulatedCountriesByCountryIdsDB:', err);
        return undefined; // 捕获错误后返回明确值
    }
}

3. 修正获取单个国家的逻辑

使用Array.find()替代filter(),获取单个匹配的Country对象:

const countries = await getPopulatedCountriesByCountryIdsDB(countriesIds!);
if (!countries) {
    // 处理未获取到国家数据的情况,比如抛出错误或返回空值
    return;
}
// find返回单个Country对象或undefined
const country = countries.find(country => country.id.equals(countryId));
if (!country) {
    // 处理未找到对应国家的情况
    return;
}
// 此时country是Country类型,可正常访问cities
const cities = country.cities.filter(city => city.id.equals(cityId));

注意:MongoDB的ObjectId是引用类型,直接用===比较会因为引用地址不同导致匹配失败,必须用equals()方法进行值比较。

内容的提问来源于stack exchange,提问作者Anatoly

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.14 00:15:33