我正在使用Firestore和Typescript。
对于数据模型,我有类型定义。例如User
可能是这样的:
interface User {
name: string;
age: number;
}
用户以唯一名称/ ID存储在users
集合中的数据库中。
在查询集合时,在Firebase中,文档的ID在文档引用中可用,并且不附带数据。在前端的常见用例中,您希望使用其ID检索记录数组,因为您可能希望与它们进行交互并需要识别每个记录。
所以我做了一个类似于下面代码的查询,其中id被合并到结果数组中:
async function getUsers(): Promise<any[]> {
const query = db.collection("users")
const snapshot = await query.get();
const results = snapshot.docs.map(doc => {
return { ...doc.data(), id: doc.id };
});
}
现在的问题是,我有一个用户类型,但由于它不包含id
字段,因此无法在此处使用。
一个天真的解决方案可能是创建一个新类型:
interface UserWithId extends User {
id: string
}
并编写如下函数:
async function getUsers(): Promise<UserWithId[]> {}
但这对我来说并不合适,因为你必须为许多类型做这件事。
我认为更好的解决方案是创建泛型类型:
type DatabaseRecord<T> = {
id: string,
data: T
}
因此,在返回的结果中保持数据和id分开:
const results = snapshot.docs.map(doc => {
return { data: doc.data(), id: doc.id };
});
...并使用函数签名:
async function getUsers(): Promise<DatabaseRecord<User>[]> {}
我倾向于第一个解决方案,因为为每个案例创建新类型感觉很愚蠢。但我仍然不确定这是否是最佳方法。
这似乎是一种常见的情况,但我没有找到任何关于此的文档。我看到开发人员只是在模型数据中写id
,基本上在其数据中复制了文档名称,但对我来说这似乎是一个很大的错误。
我可以想象如果你不使用Typescript(Flow),你只是不关心结果结构,只是将id与数据合并,但这是我真正喜欢使用类型的原因之一JS中的注释。它会迫使您更多地考虑您的数据,并最终编写更清晰的代码。