如何将动态转换器与 firebase 和 TypeScript 结合使用?

iam*_*lli 8 firebase typescript google-cloud-firestore

我正在尝试动态地将转换器传递给firebases withConverter。如果您查看 上的文档FirestoreDataConverter,如果将转换器直接传递到 ,则提供的示例可以工作withConverter

// I have modified Post Class as seen in the docs, with additional types
class Post {
  constructor(readonly title: string, readonly author: string) {
    this.title = title;
    this.author = author;
  }

  toString(): string {
    return `${this.title}, by ${this.author}`;
  }
}

type PostConverterType = firebase.firestore.FirestoreDataConverter<Post>;

// Example converter from the docs
const postConverter: PostConverterType = {
  toFirestore(post: Post): firebase.firestore.DocumentData {
    return { title: post.title, author: post.author };
  },
  fromFirestore(
    snapshot: firebase.firestore.QueryDocumentSnapshot,
    options: firebase.firestore.SnapshotOptions
  ): Post {
    const data = snapshot.data(options);
    return new Post(data.title, data.author);
  },
};

// Example when the converter is passed directly into with conveter
// This works without throwing warning.
const postSnap = await firebase
  .firestore()
  .collection('posts')
  .withConverter(postConverter) // Works like a charm, but not ideal for reuse
  .doc()
  .get();
const post = postSnap.data();

if (post !== undefined) {
  console.log({
    title: post.title, // string
    toString: post.toString(), // string
  });
}

Run Code Online (Sandbox Code Playgroud)

上述方法有效,但在我的情况下不太可重用。我头痛的是如何将转换器作为变量传递到像这样的可重用函数中.withConverter(converterVaribleFromProps)

例如,如果我添加另一个数据来转换,如作者

// Sample Author Format
class Author {
  constructor(readonly name: string, readonly email: string) {
    this.name = name;
    this.email = email;
  }
}

type AuthorConverterType = firebase.firestore.FirestoreDataConverter<Author>;

const authorConverter: AuthorConverterType = {
  toFirestore(author: Author): firebase.firestore.DocumentData {
    return { title: author.name, author: author.email };
  },
  fromFirestore(
    snapshot: firebase.firestore.QueryDocumentSnapshot,
    options: firebase.firestore.SnapshotOptions
  ): Author {
    const data = snapshot.data(options);
    return new Author(data.title, data.author);
  },
};
Run Code Online (Sandbox Code Playgroud)

在这一点上,我有一个Authors只关心 的视图authorConverter和一个Posts针对 的视图postConverter。我创建了一个可重用的函数,它接受集合和转换器并将它们传递给 firebase。对两种视图进行大量重复逻辑。


export const connectToDbFromAnyContext = (
  collection: 'posts' | 'users' = 'posts',
  converter: PostConverterType | AuthorConverterType // 1.  I am stuck here
): (() => void) => {
  // Tried to test typeof converter here
  // and do conditional checks by in vain
  console.log({ 'converterType': typeof converter });

  const unsubscribeDb = firebase
    .firestore()
    .collection(collection)
    .withConverter(converter) // 2.  Because this complains
    .onSnapshot(
      (snapshot) => {
        const newData = snapshot.docs.map((doc) => ({
          ...doc.data(),
          id: doc.id,
        }));

        // Update state with newTimes
        console.log({ newData });
      },
      (error) => {
        console.log({ error });
      }
    );

  // Do some other stuff here
  // ...and alot or other repeatitive logic

  return unsubscribeDb;
};

Run Code Online (Sandbox Code Playgroud)

正如您在 Comment 中看到的1,我正在尝试使用 Union 类型,converter: PostConverterType | AuthorConverterType但 TSlint 会抛出此错误...2

Argument of type 'PostConverterType | AuthorConverterType' is not assignable to parameter of type 'FirestoreDataConverter<Post>'.
  Type 'AuthorConverterType' is not assignable to type 'FirestoreDataConverter<Post>'.
    Types of property 'toFirestore' are incompatible.
      Type '{ (modelObject: Author): DocumentData; (modelObject: Partial<Author>, options: SetOptions): DocumentData; }' is not assignable to type '{ (modelObject: Post): DocumentData; (modelObject: Partial<Post>, options: SetOptions): DocumentData; }'.
        Types of parameters 'modelObject' and 'modelObject' are incompatible.
          Type 'Post' is missing the following properties from type 'Author': name, emailts(2345)
Run Code Online (Sandbox Code Playgroud)

请帮忙。谢谢。