TypeScript:根据字符串数组返回对应类型MongoDB集合数组的问题
问题
我希望创建一个函数,根据传入的字符串数组返回所需的MongoDB集合。目前我的实现代码如下:
type CollectionNames = 'users' | 'orders'; type CollectionMap = { users: User; orders: Order; }; type CollectionsArray<T extends CollectionNames[]> = { [K in keyof T]: mongodb.Collection<CollectionMap[T[K]]>; }; type CollectionAndConn<T extends CollectionNames[]> = { conn: mongodb.MongoClient; collections: CollectionsArray<T>; //mongodb.Collection<CollectionMap[T]>[]; }; export const mongo = async <T extends CollectionNames[]>(collectionNames: T): Promise<CollectionAndConn<T>> => { const conn = await MongoClient.connect(`${MONGO_URL}`, {}); return { conn, collections: collectionNames.map((collectionName) => conn.db().collection(collectionName)) as CollectionsArray<T>, }; };
我期望按如下方式调用该函数:
const { conn, collections: [usersCollection, ordersCollection], } = await mongo(['users', 'orders']);
但当前TypeScript会将usersCollection和ordersCollection都推断为mongodb.Collection<User | Order>,而我需要它根据传入的字符串数组,正确识别usersCollection为mongodb.Collection<User>,ordersCollection为mongodb.Collection<Order>。
解决方案
问题核心是TypeScript默认会把['users', 'orders']推断为CollectionNames[](元素为联合类型的普通数组),而非保留每个元素具体类型的元组。要实现精准类型推断,需做以下调整:
1. 调整泛型约束为只读元组
修改函数的泛型参数,让T约束为readonly CollectionNames[],这样TypeScript能更好地识别元组类型:
export const mongo = async <T extends readonly CollectionNames[]>(collectionNames: T): Promise<CollectionAndConn<T>> => { const conn = await MongoClient.connect(`${MONGO_URL}`, {}); return { conn, collections: collectionNames.map((collectionName) => conn.db().collection(collectionName)) as CollectionsArray<T>, }; };
2. 调用参数添加const断言
调用函数时,给数组加上as const,强制TypeScript将其推断为只读元组,保留每个元素的具体类型:
const { conn, collections: [usersCollection, ordersCollection], } = await mongo(['users', 'orders'] as const);
优化类型定义(可选)
为了避免潜在的类型歧义,可以优化CollectionsArray的定义,用Extract确保元素类型被正确缩小:
type CollectionsArray<T extends readonly CollectionNames[]> = { [K in keyof T]: mongodb.Collection<CollectionMap[Extract<T[K], CollectionNames>]>; };
完成以上修改后,TypeScript就能精准推断:
usersCollection类型为mongodb.Collection<User>ordersCollection类型为mongodb.Collection<Order>
内容的提问来源于stack exchange,提问作者m0rfarpeter
相关产品推荐
相关产品推荐

