如何获得对 MongoDB 集合的通用和静态引用?
How do I get a Generic and static reference to a MongoDB collection?
我想编写一个静态 getOne<T>()
class 方法(即它不需要 class 实例或 new
运算符来使用它)这也是泛型,which returns MongoDB 对象作为 Item
,即 Book
或 Film
。这是我最初的想法,但现在我不知道如何动态地使用 'books'
或 'films'
集合名称字符串来代替 'xxx'
.
import * as mongodb from 'mongodb';
const CONNECTION_STRING = 'MY_CONNECTION_STRING';
const BOOK_COLLECTION_NAME = 'books';
const FILM_COLLECTION_NAME = 'films';
interface Item {
_id: string
}
interface Book extends Item {
bookName: string,
description?: string
}
interface Film extends Item {
filmTitle: string,
duration?: number
}
function isBook(item: Item): item is Book {
return 'bookName' in item;
}
async function getOne<T extends Item>(): Promise<T | null> {
const client = new mongodb.MongoClient(CONNECTION_STRING);
await client.connect();
const db = client.db();
const collection = db.collection<T>('xxx');
// Instead of xxx I need to use BOOK_COLLECTION_NAME or FILM_COLLECTION_NAME
// depending on the actual type of T, how do I do that???
const item = await collection.findOne({});
if (item !== null) {
console.log(item._id);
if (isBook(item)) {
// Book type specific implementation
item.bookName += ' (best book ever)';
}
}
return item as T;
}
async function test() {
const book: Book | null = await getOne<Book>();
console.log(book?.bookName);
const film: Film | null = await getOne<Film>();
console.log(film?.filmTitle);
}
test();
这可能吗?我意识到我可以解决这个问题,将它作为参数传递给 await getOne<Book>('books')
之类的东西,但我想防止这种情况发生(有关所需用法,请参阅 test()
函数)。
这不能用您想要的确切 API 来完成,因为函数在运行时无法访问您传递给函数的类型参数(以推断 table 名称)。您可以使用另一种方法,其中 interface
的名称是从集合名称中推断出来的,因此传递 'books'
returns Book | null
,传递 'films'
returns Film | null
,传递任何其他内容都是编译时错误。
type Collections = {
books: Book,
films: Film,
}
async function getOne<Name extends keyof Collections>(name: Name): Promise<Collections[Name] | null> {
// fetch the actual value here
return {} as Collections[Name];
}
async function test() {
const book: Book | null = await getOne('books');
console.log(book?.bookName);
const film: Film | null = await getOne('films');
console.log(film?.filmTitle);
// Argument of type '"comments"' is not assignable to parameter of type 'keyof Collections'.
await getOne('comments');
}
test();
我想编写一个静态 getOne<T>()
class 方法(即它不需要 class 实例或 new
运算符来使用它)这也是泛型,which returns MongoDB 对象作为 Item
,即 Book
或 Film
。这是我最初的想法,但现在我不知道如何动态地使用 'books'
或 'films'
集合名称字符串来代替 'xxx'
.
import * as mongodb from 'mongodb';
const CONNECTION_STRING = 'MY_CONNECTION_STRING';
const BOOK_COLLECTION_NAME = 'books';
const FILM_COLLECTION_NAME = 'films';
interface Item {
_id: string
}
interface Book extends Item {
bookName: string,
description?: string
}
interface Film extends Item {
filmTitle: string,
duration?: number
}
function isBook(item: Item): item is Book {
return 'bookName' in item;
}
async function getOne<T extends Item>(): Promise<T | null> {
const client = new mongodb.MongoClient(CONNECTION_STRING);
await client.connect();
const db = client.db();
const collection = db.collection<T>('xxx');
// Instead of xxx I need to use BOOK_COLLECTION_NAME or FILM_COLLECTION_NAME
// depending on the actual type of T, how do I do that???
const item = await collection.findOne({});
if (item !== null) {
console.log(item._id);
if (isBook(item)) {
// Book type specific implementation
item.bookName += ' (best book ever)';
}
}
return item as T;
}
async function test() {
const book: Book | null = await getOne<Book>();
console.log(book?.bookName);
const film: Film | null = await getOne<Film>();
console.log(film?.filmTitle);
}
test();
这可能吗?我意识到我可以解决这个问题,将它作为参数传递给 await getOne<Book>('books')
之类的东西,但我想防止这种情况发生(有关所需用法,请参阅 test()
函数)。
这不能用您想要的确切 API 来完成,因为函数在运行时无法访问您传递给函数的类型参数(以推断 table 名称)。您可以使用另一种方法,其中 interface
的名称是从集合名称中推断出来的,因此传递 'books'
returns Book | null
,传递 'films'
returns Film | null
,传递任何其他内容都是编译时错误。
type Collections = {
books: Book,
films: Film,
}
async function getOne<Name extends keyof Collections>(name: Name): Promise<Collections[Name] | null> {
// fetch the actual value here
return {} as Collections[Name];
}
async function test() {
const book: Book | null = await getOne('books');
console.log(book?.bookName);
const film: Film | null = await getOne('films');
console.log(film?.filmTitle);
// Argument of type '"comments"' is not assignable to parameter of type 'keyof Collections'.
await getOne('comments');
}
test();