@@ -696,78 +696,81 @@ describe('FirestoreTypeConverter', () => {
696696 }
697697 } ) ;
698698
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 } , { } > ( ) ;
705702 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+ } ) ) ;
710706
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 } > ( ) ;
714710 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.
716721 await setDoc ( docRefWithConverter , { foo : 42 } ) ;
717- }
718- } ) ;
722+ } ) ) ;
719723
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 } > ( ) ;
726727 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+ } ) ) ;
731730
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 } > ( ) ;
735734 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+ } ) ) ;
740738
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 } > ( ) ;
747751 const docRefWithConverter = docRef . withConverter ( converter ) ;
748752 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+ } ) ;
753756
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 { }
768765
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