From 0673e3c034d1a91c05d76a075e9dd1c681c72cd6 Mon Sep 17 00:00:00 2001 From: Richard Scotten Date: Sat, 21 Mar 2020 14:23:27 -0700 Subject: [PATCH 1/7] fixed type orders --- index.d.ts | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/index.d.ts b/index.d.ts index 6473c7fbf..68e462e82 100644 --- a/index.d.ts +++ b/index.d.ts @@ -809,12 +809,12 @@ export function firebaseConnect( export function firebaseReducer< UserType, Schema extends Record> ->(state: any, action: any): FirebaseReducer.Reducer +>(state: any, action: any): FirebaseReducer.Reducer export function makeFirebaseReducer< - Schema extends Record>, - UserType = {} ->(): (state: any, action: any) => FirebaseReducer.Reducer + UserType = {}, + Schema extends Record> = {} +>(): (state: any, action: any) => FirebaseReducer.Reducer /** * React HOC that attaches/detaches Cloud Firestore listeners on mount/unmount @@ -1037,7 +1037,9 @@ export interface ReduxFirestoreConfig { preserveOnListenerError: null | object // https://github.com/prescottprue/redux-firestore#onattemptcollectiondelete - onAttemptCollectionDelete: null | ((queryOption: any, dispatch: any, firebase: any) => void) + onAttemptCollectionDelete: + | null + | ((queryOption: any, dispatch: any, firebase: any) => void) // https://github.com/prescottprue/redux-firestore#mergeordered mergeOrdered: boolean @@ -1128,8 +1130,8 @@ export interface Data { export namespace FirebaseReducer { export interface Reducer< - Schema extends Record>, - ProfileType = {} + ProfileType = {}, + Schema extends Record> = {} > { auth: AuthState profile: Profile From 80082f68dd450b44d0096b8edc7b2b64f0d4bc70 Mon Sep 17 00:00:00 2001 From: Richard Scotten Date: Sun, 5 Apr 2020 21:25:38 -0700 Subject: [PATCH 2/7] fixed type and added docs --- docs/getting_started.md | 72 +++++++++++++++++++++++++++++++++++++---- index.d.ts | 8 ++--- 2 files changed, 70 insertions(+), 10 deletions(-) diff --git a/docs/getting_started.md b/docs/getting_started.md index 7694bc67a..a31e2f785 100644 --- a/docs/getting_started.md +++ b/docs/getting_started.md @@ -7,6 +7,7 @@ Install peer dependencies: `npm i --save redux react-redux` ## Install + ```bash npm install --save react-redux-firebase ``` @@ -25,6 +26,62 @@ const rootReducer = combineReducers({ }) ``` +## Add Reducer using Typescript: + +We provide optional `Profile` and `Schema` types for additional type checking. + +You can add the `Profile` type if you use the [Profile option](https://react-redux-firebase.com/docs/recipes/profile.html). + +You can define a `Schema` that corresponds to your Firebase Redux store for `state.firebase.data` and `state.firebase.ordered`. That could be a map of your Realtime Database collections, or anything else if you use `storeAs` to name custom stores. + +```typescript +import { combineReducers } from 'redux' +import { firebaseReducer, FirebaseReducer } from 'react-redux-firebase' + +// Optional: If you use the user profile option +interface Profile { + name: string + email: string +} + +// If you have a todos collection, you might have this type +interface Todo { + text: string + completed: boolean +} + +// Optional: You can define the schema of your Firebase Redux store. +// This will give you type-checking for state.firebase.data.todos and state.firebase.ordered.todos +interface Schema { + todos: Todo +} + +// with both reducer types +interface RootState { + firebase: FirebaseReducer.Reducer +} + +// with only Profile type +interface RootState { + firebase: FirebaseReducer.Reducer<{Profile> +} + +// with only Schema type +interface RootState { + firebase: FirebaseReducer.Reducer<{}, Schema> +} + +// without reducer types +interface RootState { + firebase: FirebaseReducer.Reducer +} + + +const rootReducer = combineReducers({ + firebase: firebaseReducer +}) +``` + ## Setting Up App With Store ```javascript @@ -36,14 +93,17 @@ import 'firebase/auth' // import 'firebase/firestore' // <- needed if using firestore // import 'firebase/functions' // <- needed if using httpsCallable import { createStore, combineReducers, compose } from 'redux' -import { ReactReduxFirebaseProvider, firebaseReducer } from 'react-redux-firebase' +import { + ReactReduxFirebaseProvider, + firebaseReducer +} from 'react-redux-firebase' // import { createFirestoreInstance, firestoreReducer } from 'redux-firestore' // <- needed if using firestore const fbConfig = {} // react-redux-firebase config const rrfConfig = { - userProfile: 'users', + userProfile: 'users' // useFirestoreForProfile: true // Firestore for Profile instead of Realtime DB // enableClaims: true // Get custom claims along with the profile } @@ -57,7 +117,7 @@ firebase.initializeApp(fbConfig) // Add firebase to reducers const rootReducer = combineReducers({ - firebase: firebaseReducer, + firebase: firebaseReducer // firestore: firestoreReducer // <- needed if using firestore }) @@ -68,7 +128,7 @@ const store = createStore(rootReducer, initialState) const rrfProps = { firebase, config: rrfConfig, - dispatch: store.dispatch, + dispatch: store.dispatch // createFirestoreInstance // <- needed if using firestore } @@ -80,8 +140,8 @@ function App() { - ); + ) } -render(, document.getElementById('root')); +render(, document.getElementById('root')) ``` diff --git a/index.d.ts b/index.d.ts index 68e462e82..296487b53 100644 --- a/index.d.ts +++ b/index.d.ts @@ -807,13 +807,13 @@ export function firebaseConnect( * @see https://react-redux-firebase.com/docs/api/reducer.html */ export function firebaseReducer< - UserType, - Schema extends Record> + UserType extends Record = {}, + Schema extends Record = {} >(state: any, action: any): FirebaseReducer.Reducer export function makeFirebaseReducer< - UserType = {}, - Schema extends Record> = {} + UserType extends Record = {}, + Schema extends Record = {} >(): (state: any, action: any) => FirebaseReducer.Reducer /** From 2e8858058e0d7b510241360692e7faa61feb093e Mon Sep 17 00:00:00 2001 From: Richard Scotten Date: Sun, 5 Apr 2020 21:35:39 -0700 Subject: [PATCH 3/7] fixed typo --- docs/getting_started.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/getting_started.md b/docs/getting_started.md index a31e2f785..192804f4e 100644 --- a/docs/getting_started.md +++ b/docs/getting_started.md @@ -63,7 +63,7 @@ interface RootState { // with only Profile type interface RootState { - firebase: FirebaseReducer.Reducer<{Profile> + firebase: FirebaseReducer.Reducer } // with only Schema type From cfc516c428883a7845d6f9fc8ee671ce80e808f7 Mon Sep 17 00:00:00 2001 From: Richard Scotten Date: Sun, 5 Apr 2020 21:50:30 -0700 Subject: [PATCH 4/7] Update index.d.ts --- index.d.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/index.d.ts b/index.d.ts index 296487b53..c874f5c95 100644 --- a/index.d.ts +++ b/index.d.ts @@ -804,7 +804,7 @@ export function firebaseConnect( * @param action.type - Type of Action being called * @param action.path - Path of action that was dispatched * @param action.data - Data associated with action - * @see https://react-redux-firebase.com/docs/api/reducer.html + * @see https://react-redux-firebase.com/docs/getting_started.html#add-reducer */ export function firebaseReducer< UserType extends Record = {}, From 9feabb83f5dec3ae35ac68d6be4cedf4f8046010 Mon Sep 17 00:00:00 2001 From: Richard Scotten Date: Sun, 5 Apr 2020 22:09:42 -0700 Subject: [PATCH 5/7] Update index.d.ts --- index.d.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/index.d.ts b/index.d.ts index c874f5c95..6d090604d 100644 --- a/index.d.ts +++ b/index.d.ts @@ -1130,8 +1130,8 @@ export interface Data { export namespace FirebaseReducer { export interface Reducer< - ProfileType = {}, - Schema extends Record> = {} + ProfileType extends Record = {}, + Schema extends Record = {} > { auth: AuthState profile: Profile From bf1c97a8124d09688418a3b54c4601a015520f59 Mon Sep 17 00:00:00 2001 From: Richard Scotten Date: Sun, 5 Apr 2020 22:10:59 -0700 Subject: [PATCH 6/7] Update index.d.ts --- index.d.ts | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/index.d.ts b/index.d.ts index 6d090604d..068b18597 100644 --- a/index.d.ts +++ b/index.d.ts @@ -807,14 +807,14 @@ export function firebaseConnect( * @see https://react-redux-firebase.com/docs/getting_started.html#add-reducer */ export function firebaseReducer< - UserType extends Record = {}, + ProfileType extends Record = {}, Schema extends Record = {} ->(state: any, action: any): FirebaseReducer.Reducer +>(state: any, action: any): FirebaseReducer.Reducer export function makeFirebaseReducer< - UserType extends Record = {}, + ProfileType extends Record = {}, Schema extends Record = {} ->(): (state: any, action: any) => FirebaseReducer.Reducer +>(): (state: any, action: any) => FirebaseReducer.Reducer /** * React HOC that attaches/detaches Cloud Firestore listeners on mount/unmount From 1222fbc625155d3e8fbef039c0975ce68b205d29 Mon Sep 17 00:00:00 2001 From: Richard Scotten Date: Sun, 31 May 2020 13:15:10 -0700 Subject: [PATCH 7/7] fixed types --- index.d.ts | 69 +++++++++++++++++++++++++++++++++--------------------- 1 file changed, 42 insertions(+), 27 deletions(-) diff --git a/index.d.ts b/index.d.ts index 00c0400ea..89dd2e33e 100644 --- a/index.d.ts +++ b/index.d.ts @@ -10,6 +10,8 @@ import { Dispatch } from 'redux' */ type Omit = Pick> +type FileOrBlob = T extends File ? File : Blob + /** * Injects props and removes them from the prop requirements. * Will not pass through the injected props if they are passed in during @@ -738,11 +740,11 @@ interface ExtendedStorageInstance { * @param options.documentId - Id of document to update with metadata if using Firestore * @see https://react-redux-firebase.com/docs/api/storage.html#uploadFile */ - uploadFile: ( + uploadFile: ( path: string, - file: File | Blob, + file: FileOrBlob, dbPath?: string, - options?: UploadFileOptions + options?: UploadFileOptions ) => Promise<{ uploadTaskSnapshot: StorageTypes.UploadTaskSnapshot }> /** @@ -758,42 +760,46 @@ interface ExtendedStorageInstance { * @param options.documentId - Id of document to update with metadata if using Firestore * @see https://react-redux-firebase.com/docs/api/storage.html#uploadFiles */ - uploadFiles: ( + uploadFiles: ( path: string, - files: File[] | Blob[], + files: FileOrBlob[], dbPath?: string, - options?: UploadFileOptions + options?: UploadFileOptions ) => Promise<{ uploadTaskSnapshot: StorageTypes.UploadTaskSnapshot }[]> } /** * Configuration object passed to uploadFile and uploadFiles functions */ -export interface UploadFileOptions { - name?: string | (( - file: File | Blob, - internalFirebase: WithFirebaseProps['firebase'], - uploadConfig: { - path: string, - file: File | Blob, - dbPath?: string, - options?: UploadFileOptions - } - ) => string) - documentId?: string | (( - uploadRes: StorageTypes.UploadTaskSnapshot, - firebase: WithFirebaseProps['firebase'], - metadata: StorageTypes.UploadTaskSnapshot['metadata'], - downloadURL: string - ) => string) +export interface UploadFileOptions { + name?: + | string + | (( + file: FileOrBlob, + internalFirebase: WithFirebaseProps['firebase'], + uploadConfig: { + path: string + file: FileOrBlob + dbPath?: string + options?: UploadFileOptions + } + ) => string) + documentId?: + | string + | (( + uploadRes: StorageTypes.UploadTaskSnapshot, + firebase: WithFirebaseProps['firebase'], + metadata: StorageTypes.UploadTaskSnapshot['metadata'], + downloadURL: string + ) => string) useSetForMetadata?: boolean metadata?: StorageTypes.UploadMetadata - metadataFactory? : (( + metadataFactory?: ( uploadRes: StorageTypes.UploadTaskSnapshot, firebase: WithFirebaseProps['firebase'], metadata: StorageTypes.UploadTaskSnapshot['metadata'], downloadURL: string - ) => object) + ) => object } export interface WithFirebaseProps { @@ -1032,11 +1038,20 @@ interface ReactReduxFirebaseConfig { /** * Function for changing how profile is written to database (both RTDB and Firestore). */ - profileFactory?: (userData?: AuthTypes.User, profileData?: any, firebase?: WithFirebaseProps['firebase']) => Promise | any + profileFactory?: ( + userData?: AuthTypes.User, + profileData?: any, + firebase?: WithFirebaseProps['firebase'] + ) => Promise | any /** * Function that returns that meta data object stored after a file is uploaded (both RTDB and Firestore). */ - fileMetadataFactory?: (uploadRes: StorageTypes.UploadTaskSnapshot, firebase: WithFirebaseProps['firebase'], metadata: StorageTypes.UploadTaskSnapshot.metadata, downloadURL: string) => object + fileMetadataFactory?: ( + uploadRes: StorageTypes.UploadTaskSnapshot, + firebase: WithFirebaseProps['firebase'], + metadata: StorageTypes.UploadTaskSnapshot.metadata, + downloadURL: string + ) => object } /**