如何自定义firebase DocumentData 接口?
Posted
技术标签:
【中文标题】如何自定义firebase DocumentData 接口?【英文标题】:How to customise firebase DocumentData interface? 【发布时间】:2019-05-09 12:26:16 【问题描述】:我正在使用 firebase@5.5.8 和 typescript@3.1.4
每当我从 firestore 创建一个文档时,我都会得到一个 firebase.firestore.DocumentReference
类型的对象,正如预期的那样
如果我调用get(options?: firebase.firestore.GetOptions|undefined)
,我将按预期获得firebase.firestore.DocumentSnapshot
类型的对象
如果我打电话给data(options?: firebase.firestore.DataOptions|undefined)
,我将得到一个 firebase.firestore.DocumentData 对象或未定义的对象,正如预期的那样
现在,在我的 manager 对象上,我知道我在向数据库写入什么,所以我可以断言无论你从我的 manager 中得到什么 DocumentData,你都会得到一个如图所示的 Client
export interface Client
name: string;
website?: string;
description?: string;
visible: boolean;
我想为我的管理器对象创建一个接口来表达这一点。所以我试过了:
export interface FirebaseDocumentSnapshot<T> extends $firebase.firestore.DocumentSnapshot
data(options?: $firebase.firestore.SnapshotOptions | undefined): T|undefined
export interface FirebaseDocumentReference<T> extends $firebase.firestore.DocumentReference
get(options?: $firebase.firestore.GetOptions | undefined): Promise<FirebaseDocumentSnapshot<T>>
我遇到的问题在这里:
const client: Client = mapClient(args);
const result: FirebaseDocumentReference<Client> = await $db.add(client);
错误是:
[ts]
Type 'DocumentReference' is not assignable to type 'FirebaseDocumentReference<Client>'.
Types of property 'get' are incompatible.
Type '(options?: GetOptions | undefined) => Promise<DocumentSnapshot>' is not assignable to type '(options?: GetOptions | undefined) => Promise<FirebaseDocumentSnapshot<Client>>'.
Type 'Promise<DocumentSnapshot>' is not assignable to type 'Promise<FirebaseDocumentSnapshot<Client>>'.
Type 'DocumentSnapshot' is not assignable to type 'FirebaseDocumentSnapshot<Client>'.
Types of property 'data' are incompatible.
Type '(options?: SnapshotOptions | undefined) => DocumentData | undefined' is not assignable to type '(options?: SnapshotOptions | undefined) => Client | undefined'.
Type 'DocumentData | undefined' is not assignable to type 'Client | undefined'.
Type 'DocumentData' is not assignable to type 'Client'.
Property 'name' is missing in type 'DocumentData'. [2322]
const result: FirebaseDocumentReference<Client>
如何声明接口以便知道结果对象的类型?
【问题讨论】:
为什么不直接转换 data() 返回的对象呢?例如:const client = snapshot.data() as Client
?
因为我想返回 DocumentReference 并访问所有的 firebase 好东西,而不是返回原始数据对象
我想我不明白你为什么需要一个特殊的泛型类型 DocumentReference。
好吧。我有一个管理器服务,它控制我的应用程序对 firebase 的访问,特别是在创建新记录时,我希望从该管理器服务中返回它创建的任何实体的 DocumentReference。并且使用 TypeScript,我希望能够知道一旦获得该文档引用的数据,我将获得什么类型的数据。此外,DocumentData 有什么用?为什么 DocumentSnapshot.get() 只返回任何|未定义?或者只是任何事情
没有看到你的整个系统,真的很难理解为什么这比仅仅转换到一个界面更有帮助。您的代码将不得不对该文档中的内容做出假设,并且演员表与做出该假设的任何方式一样好。
【参考方案1】:
一个简单的解决方案是转换返回数据:
const client = snapshot.data() as Client
【讨论】:
【参考方案2】:@gal-bracha 的解决方案将“工作”,因为 TypeScript 编译器将假定 client
的类型为 Client
,但如果错误数据最终出现在 Firestore 中,它并不能防止运行时错误。在处理应用程序外部的任何数据时,更安全的解决方案是使用 Yup 之类的东西来明确地验证数据:
import * as yup from "yup";
const clientSchema = yup.object(
name: yup.string(),
website: yup.string().url().notRequired(),
description: yup.string().notRequired(),
visible: yup.boolean()
);
// You can use this elsewhere in your app
export type Client = yup.InferType<typeof clientSchema>;
// Usage
const client = await clientSchema.validate(snapshot.data());
这更具防御性,因为如果由于某种原因,不良数据最终进入 Firestore,clientSchema.validate
将引发错误。在validate()
之后,您可以保证client
是Client
,而不仅仅是告诉TypeScript 编译器“将其视为Client
,即使在运行时也可能不是”。
【讨论】:
以上是关于如何自定义firebase DocumentData 接口?的主要内容,如果未能解决你的问题,请参考以下文章
如何自定义firebase DocumentData 接口?
如何将自定义参数与保留事件一起发送到 Firebase 分析
如何从 Android 中的 Firebase 应用内消息中检索自定义数据