firebase-admin-node icon indicating copy to clipboard operation
firebase-admin-node copied to clipboard

Allow generic in onDocumentUpdated, onDocumentCreated, etc...

Open cedvdb opened this issue 2 years ago • 0 comments

Problem:

Making a wrapper class where types can be inferred is not possible.

Goal:

 onDocumentUpdated<Payment>(  // note the modified declaration below
  `${Col.payments}/{paymentID}`,
  handlers.authorizePayment,
);

with changes to the declaration such as:


// firestore.d.ts
export declare function onDocumentUpdated<Data extends DocumentData, Document extends string>(document: Document, handler: (event: FirestoreEvent<Change<QueryDocumentSnapshot<T>> | undefined, ParamsOf<Document>>) => any | Promise<any>): CloudFunction<FirestoreEvent<Change<QueryDocumentSnapshot> | undefined, ParamsOf<Document>>>;

Use case:

It will be possible to write things like:


export type UpdateEvent<T> = FirestoreEvent<Change<QueryDocumentSnapshot<T>> | undefined>;


class AuthorizePaymentOnValidatedTrigger implements OnUpdate<Payment> {
   handle(event: UpdateEvent<Payment>) {
  // ...
  }
}

Currently I'm using a wrapper:

/// Used to create firebase triggers without having to cast
export abstract class Triggers {

  static onDocumentUpdated<T extends Identifiable>(path: string, handler: OnUpdateHandler<T>) {
    return onDocumentUpdated(path, (event) => handler.handle(event as UpdateEvent<T>));
  }

  static onDocumentCreated<T extends Identifiable>(path: string, handler: OnCreateHandler<T>) {
    return onDocumentCreated(path, (event) => handler.handle(event as CreateEvent<T>));
  }

  static onDocumentDeleted<T extends Identifiable>(path: string, handler: OnDeleteHandler<T>) {
    return onDocumentDeleted(path, (event) => handler.handle(event as DeleteEvent<T>));
  }
}

export type UpdateEvent<T> = FirestoreEvent<Change<QueryDocumentSnapshot<T>>>;

export interface OnUpdateHandler<T extends Identifiable> {
  handle(event: UpdateEvent<T>): Promise<void>;
}

export type CreateEvent<T> = FirestoreEvent<QueryDocumentSnapshot<T>>;

export interface OnCreateHandler<T extends Identifiable> {
  handle(event: CreateEvent<T>): Promise<void>;
}

export type DeleteEvent<T> = FirestoreEvent<QueryDocumentSnapshot<T>>;

export interface OnDeleteHandler<T extends Identifiable> {
  handle(deleted: DeleteEvent<T>): Promise<void>;
}


together with #2202 would allow:

handle(event: UpdateEvent<Payment>) {
   const { before, after } = event.data;
}

instead of

handle(event: UpdateEvent) {
    const data = event.data;
    if (!data) return;
    const before = data.before.data() as Payment;
    const after = data.after.data() as Payment;
}

cedvdb avatar May 30 '23 10:05 cedvdb