@@ -696,78 +696,81 @@ describe('FirestoreTypeConverter', () => {
696
696
}
697
697
} ) ;
698
698
699
- it ( 'setDoc() fails to compile if `data` argument is missing properties' , ( ) => {
700
- async function _ ( docRef : DocumentReference ) : Promise < void > {
701
- const converter = new ThrowingConverter <
702
- { foo : string } ,
703
- { bar : number }
704
- > ( ) ;
699
+ it ( 'setDoc() fails to compile if AppModelType argument is missing properties' , ( ) =>
700
+ neverCall ( async docRef => {
701
+ const converter = fakeConverter < { foo : string } , { } > ( ) ;
705
702
const docRefWithConverter = docRef . withConverter ( converter ) ;
706
- // @ts -expect-error `data` argument is missing `foo` property.
707
- await setDoc ( docRefWithConverter , { bar : 42 } ) ;
708
- }
709
- } ) ;
703
+ // @ts -expect-error The `foo` property declared in AppModelType is missing.
704
+ await setDoc ( docRefWithConverter , { } ) ;
705
+ } ) ) ;
710
706
711
- it ( 'setDoc() fails to compile if `data` argument has incorrect type for a property ' , ( ) => {
712
- async function _ ( docRef : DocumentReference ) : Promise < void > {
713
- const converter = new ThrowingConverter < { foo : string } , { } > ( ) ;
707
+ it ( 'setDoc() fails to compile if AppModelType argument contains undeclared properties ' , ( ) =>
708
+ neverCall ( async docRef = > {
709
+ const converter = fakeConverter < { foo : string } , { bar : number } > ( ) ;
714
710
const docRefWithConverter = docRef . withConverter ( converter ) ;
715
- // @ts -expect-error The `data` argument has the wrong type for `foo`.
711
+ // @ts -expect-error The `bar` property is not declared in AppModelType.
712
+ await setDoc ( docRefWithConverter , { foo : 'foo' , bar : 42 } ) ;
713
+ } ) ) ;
714
+
715
+ it ( 'setDoc() fails to compile if AppModelType argument contains a property with an incorrect type' , ( ) =>
716
+ neverCall ( async docRef => {
717
+ const converter = fakeConverter < { foo : string } , { foo : number } > ( ) ;
718
+ const docRefWithConverter = docRef . withConverter ( converter ) ;
719
+ // @ts -expect-error The `foo` property is declared as `string` in
720
+ // AppModelType, but a `number` is specified.
716
721
await setDoc ( docRefWithConverter , { foo : 42 } ) ;
717
- }
718
- } ) ;
722
+ } ) ) ;
719
723
720
- it ( 'updateDoc() fails to compile if `data` argument is missing properties' , ( ) => {
721
- async function _ ( docRef : DocumentReference ) : Promise < void > {
722
- const converter = new ThrowingConverter <
723
- { foo : string } ,
724
- { bar : number }
725
- > ( ) ;
724
+ it ( 'updateDoc() successfully compiles even if DbModelType argument is missing properties' , ( ) =>
725
+ neverCall ( async docRef => {
726
+ const converter = fakeConverter < { foo : string } , { bar : number } > ( ) ;
726
727
const docRefWithConverter = docRef . withConverter ( converter ) ;
727
- // @ts -expect-error `data` argument is missing `bar` property.
728
- await updateDoc ( docRefWithConverter , { foo : 'foo' } ) ;
729
- }
730
- } ) ;
728
+ await updateDoc ( docRefWithConverter , { } ) ;
729
+ } ) ) ;
731
730
732
- it ( 'updateDoc() fails to compile if `data` argument has incorrect type for a property ' , ( ) => {
733
- async function _ ( docRef : DocumentReference ) : Promise < void > {
734
- const converter = new ThrowingConverter < { } , { bar : number } > ( ) ;
731
+ it ( 'updateDoc() fails to compile if DbModelType argument contains undeclared properties ' , ( ) =>
732
+ neverCall ( async docRef = > {
733
+ const converter = fakeConverter < { foo : string } , { bar : number } > ( ) ;
735
734
const docRefWithConverter = docRef . withConverter ( converter ) ;
736
- // @ts -expect-error The `data` argument has the wrong type for `bar`.
737
- await updateDoc ( docRefWithConverter , { bar : 'bar' } ) ;
738
- }
739
- } ) ;
735
+ // @ts -expect-error The `foo` property is not declared in DbModelType.
736
+ await updateDoc ( docRefWithConverter , { foo : 'foo' , bar : 42 } ) ;
737
+ } ) ) ;
740
738
741
- it ( 'getDoc() returns AppModelType' , ( ) => {
742
- async function _ ( docRef : DocumentReference ) : Promise < void > {
743
- const converter = new ThrowingConverter <
744
- { foo : string } ,
745
- { bar : number }
746
- > ( ) ;
739
+ it ( 'updateDoc() fails to compile if DbModelType argument contains a property with an incorrect type' , ( ) =>
740
+ neverCall ( async docRef => {
741
+ const converter = fakeConverter < { foo : string } , { foo : number } > ( ) ;
742
+ const docRefWithConverter = docRef . withConverter ( converter ) ;
743
+ // @ts -expect-error The `foo` property is declared as `number` in
744
+ // DbModelType, but a `string` is specified.
745
+ await updateDoc ( docRefWithConverter , { foo : 'foo' } ) ;
746
+ } ) ) ;
747
+
748
+ it ( 'getDoc() returns AppModelType' , ( ) =>
749
+ neverCall < Promise < { foo : string } > > ( async docRef => {
750
+ const converter = fakeConverter < { foo : string } , { bar : number } > ( ) ;
747
751
const docRefWithConverter = docRef . withConverter ( converter ) ;
748
752
const snapshot = await getDoc ( docRefWithConverter ) ;
749
- const data : { foo : string } = snapshot . data ( ) ! ;
750
- expect ( data . foo ) . to . equal ( 'foo' ) ;
751
- }
752
- } ) ;
753
+ return snapshot . data ( ) ! ;
754
+ } ) ) ;
755
+ } ) ;
753
756
754
- /**
755
- * An implementation of FirestoreDataConverter whose methods simply throw an
756
- * exception. Instances of this class may be useful for tests that only desire
757
- * to check the compile-time type checking but not actually invoke the
758
- * converter at runtime.
759
- */
760
- class ThrowingConverter < AppModelType , DbModelType extends DocumentData >
761
- implements FirestoreDataConverter < AppModelType , DbModelType >
762
- {
763
- toFirestore (
764
- modelObject : WithFieldValue < AppModelType >
765
- ) : WithFieldValue < DbModelType > {
766
- throw new Error ( 'ThrowingConverter.toFirestore() should not be called' ) ;
767
- }
757
+ /**
758
+ * Does nothing; however, this function can be useful in tests that only check
759
+ * the compile-time behavior of the TypeScript compiler. For example, a test
760
+ * that ensures that a certain statement successfully compiles could pass the
761
+ * code block to this function to exercise the compiler but the code will not
762
+ * actually be executed at runtime.
763
+ */
764
+ function neverCall < T > ( _ : ( docRef : DocumentReference ) => T ) : void { }
768
765
769
- fromFirestore ( snapshot : QueryDocumentSnapshot ) : AppModelType {
770
- throw new Error ( 'ThrowingConverter.fromFirestore() should not be called' ) ;
771
- }
772
- }
773
- } ) ;
766
+ /**
767
+ * Does nothing; this function does not actually exist but is merely _declared_
768
+ * to exist. This facilitates creating variables typed as FirestoreDataConverter
769
+ * with the given type parameters at compile time. This can be useful in tests
770
+ * that only check compile-time behavior of the TypeScript compiler but don't
771
+ * actually get executed at runtime.
772
+ */
773
+ declare function fakeConverter <
774
+ AppModelType ,
775
+ DbModelType extends DocumentData
776
+ > ( ) : FirestoreDataConverter < AppModelType , DbModelType > ;
0 commit comments