【问题标题】:How to customise firebase DocumentData interface?如何自定义firebase DocumentData 接口?
【发布时间】: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() 只返回任何|未定义?或者只是任何事情
  • 没有看到你的整个系统,真的很难理解为什么这比仅仅转换到一个界面更有帮助。您的代码将不得不对该文档中的内容做出假设,并且演员表与做出该假设的任何方式一样好。

标签: node.js typescript firebase google-cloud-firestore


【解决方案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() 之后,您可以保证clientClient,而不仅仅是告诉TypeScript 编译器“将其视为Client,即使在运行时也可能不是”。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2018-09-06
      • 2017-07-18
      • 2015-10-11
      • 2022-01-03
      • 2018-08-17
      • 1970-01-01
      • 1970-01-01
      • 2015-12-01
      相关资源
      最近更新 更多