I want to create a function that returns the mongo collections i need, based on a string array.
Here is where I am at right now.
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>,
};
};
And here is how I want to call it:
const {
conn,
collections: [usersCollection, ordersCollection],
} = await mongo(['users', 'orders']);
Right now my TS thinks that both userCollection and ordersCollection is a mongodb.Collection<User | Order>
where I want it to know that userCollection should be mongodb.Collection<User>
and ordersCollection should be mongodb.Collection<Order>
based on the string[] I pass to the function.
/Peter
CodePudding user response:
If you replace collectionNames: T
with collectionNames: [...T]
in the definition of mongo
, TypeScript will regard T as a tuple type and infer the correct return type:
const mongo = async <T extends CollectionNames[]>(
collectionNames: [...T]
): Promise<CollectionAndConn<T>> => {
..
}
const {
conn,
collections: [usersCollection, ordersCollection],
// (property) collections: [mongodb.Collection<User>, mongodb.Collection<Order>]
} = await mongo(['users', 'orders']);