angular / angularfire

Angular + Firebase = ❤️
https://firebaseopensource.com/projects/angular/angularfire2
MIT License
7.69k stars 2.19k forks source link

collection() missing type arguments #3081

Open imjoshnewton opened 2 years ago

imjoshnewton commented 2 years ago

There are no exported functions for the collection function that allow a type to be specified. I see reference to collection() in the docs and in the upgrade information (screenshot below) but it isn't working in my project. If I try to add a type to get a typed collection reference, I get the error: Expected 0 type arguments, but got 1.

Version info

Angular: 13.0.3

Firebase: 9.0.0

AngularFire: 7.2

Other (e.g. Ionic/Cordova, Node, browser, operating system): MacOs Montery

How to reproduce these conditions

Steps to set up and reproduce

Attempt to create a collection reference with a custom type

Sample data and security rules

The data isn't important.

Debug output

Error in VS Code: image

AngularFire Upgrade Docs: image

Expected behavior

There should be a version of the collection function that takes a type. There are version of other functions that take a type and even expect a typed CollectionReference.

Actual behavior

No function exists that takes a type.

juane1000 commented 2 years ago

Just upgraded and immediately noticed this...

nutangwari commented 2 years ago

+1

any solution or workaround for above issue ?

Methodician commented 2 years ago

I'm rolling with a work-around but it doesn't make me happy. Presumably I'll have to do another refactor when they fix this.

customerCol = collection(firestore, 'customers') as CollectionReference<CustomerI>;

I spent like an hour wrestling with this thinking I misunderstood something because when I Google about the problem, nothing comes up. Not even this issue. Surely more folks have upgraded than just us three... I hope this gets worked out soon!

Still gotta thank the team and the community for this great revamp.

imjoshnewton commented 2 years ago

I'm rolling with a work-around but it doesn't make me happy. Presumably I'll have to do another refactor when they fix this.

customerCol = collection(firestore, 'customers') as CollectionReference<CustomerI>;

I spent like an hour wrestling with this thinking I misunderstood something because when I Google about the problem, nothing comes up. Not even this issue. Surely more folks have upgraded than just us three... I hope this gets worked out soon!

Still gotta thank the team and the community for this great revamp.

I am doing something similar but slightly different. When I need to return an observable to something like collectionData, I have that behind a function in a service and add an 'as' statement to the return.

return collectionData(q, { idField: 'id'}) as Observable<Team[]>

This way I can still get a typed object in the code that consumes the observable.

kisamoto commented 1 year ago

I have a service that I use in my components for interacting with Firebase. I've added the following helper methods to deal with V9:

  _collection<T>(colPath: string) {
    // Dirty helper function to get a typed CollectionReference
    // Can change this once 3081 is fixed
    // https://github.com/angular/angularfire/issues/3081
    return collection(this.afs, colPath) as CollectionReference<T>;
  }

  _listDocs<T>(colPath: string) {
    return getDocs(this._collection<T>(colPath));
  }

  _doc<T>(docPath: string) {
    return doc(this.afs, docPath) as DocumentReference<T>;
  }

  _getDoc<T>(docPath: string) {
    return getDoc<T>(this._doc(docPath));
  }

  _addDoc<T>(colPath: string, data: T): Observable<DocumentReference<T>> {
    const col = this._collection<T>(colPath);
    return from(addDoc<T>(col, data));
  }

  _addReadDoc<T>(colPath: string, data: T): Observable<T> {
    // Helper function that not only adds a document but then instantly retrieves it
    return this._addDoc(colPath, data).pipe(
      switchMap((ref) => from(getDoc(ref))
        .pipe(
          map(doc => doc.data()),
          filterNullish(),
        ),
      ),
    );
  }

And the helper function that removes undefined:

// Helper function to filter out nullish values
// https://stackoverflow.com/a/62971842/1401034
function filterNullish<T>(): UnaryFunction<Observable<T | null | undefined>, Observable<T>> {
  return pipe(
    filter(x => x != null) as OperatorFunction<T | null |  undefined, T>
  );
}

Then I can use them elsewhere in my service with my models:

  getOrganization(pathToDoc: string){
    return this._getDoc(pathToDoc);
  }

  createOrganization(organization: Organization): Observable<Organization> {
    return this._addReadDoc('organizations', organization);
  }

It would be useful if this was better supported but for now this seems to work