Симпатичный небольшой шаблон проектирования кода, который повысит производительность вашего Firestore и сделает ваш код безопасным с помощью TypeScript.
TL;DR:Просто посмотрите этот репозиторий, чтобы посмотреть пример кода:
Если вы ищете способ добавить TypeScript в SDK Firebase V8, ознакомьтесь с другими моими статьями:
Давайте код!
Итак, недавно я поиграл с новым SDK Firebase/Firestore V9 и придумал очень простой и минимальный способ заставить его хорошо работать с TypeScript.
Единственное, что мы собираемся сделать, это создать абстракцию, которая сопоставляет все возможные коллекции в нашей БД и возвращает типизированную ссылку на коллекцию Firestore. Так как я поклонник Vue и парадигмы компонуемого кодирования, я собираюсь поместить эту абстракцию в каталог с именем composables
и в файл с именем useDb.ts
. Первое, что мы сделаем в этом файле, — инициализируем приложение firebase и получим ссылку на базу данных Firestore:
// /composables/useDb.ts // Get the imports import { initializeApp } from 'firebase/app' import { getFirestore } from 'firebase/firestore' // Init the firebase app export const firebaseApp = initializeApp({ apiKey: '### FIREBASE API KEY ###', authDomain: '### FIREBASE AUTH DOMAIN ###', projectId: '### CLOUD FIRESTORE PROJECT ID ###' }) // Export firestore incase we need to access it directly export const firestore = getFirestore()
Далее мы собираемся создать небольшую функцию, которая будет принимать имя коллекции и выдавать ссылку на коллекцию Firestore. Эта ссылка может быть передана в getDoc
или getDocs
и т. д. для чтения/записи данных:
// /composables/useDb.ts // Get the imports import { initializeApp } from 'firebase/app' import { getFirestore, collection } from 'firebase/firestore' // Init the firebase app export const firebaseApp = initializeApp({ apiKey: '### FIREBASE API KEY ###', authDomain: '### FIREBASE AUTH DOMAIN ###', projectId: '### CLOUD FIRESTORE PROJECT ID ###' }) // Export firestore incase we need to access it directly export const firestore = getFirestore() // This is just a helper to add the type to the db responses const createCollection = (collectionName: string) => { return collection(firestore, collectionName) }
Прямо сейчас эта функция на самом деле мало что делает и в некотором роде бессмысленна, ноа вот и магия... Мы собираемся сделать эту функцию универсальным типом и добавить правильный тип в коллекцию. ссылка, которую он возвращает:
// Get the imports import { initializeApp } from 'firebase/app' import { getFirestore, CollectionReference, collection, DocumentData } from 'firebase/firestore' // Init the firebase app export const firebaseApp = initializeApp({ apiKey: '### FIREBASE API KEY ###', authDomain: '### FIREBASE AUTH DOMAIN ###', projectId: '### CLOUD FIRESTORE PROJECT ID ###' }) // Export firestore incase we need to access it directly export const firestore = getFirestore() // This is just a helper to add the type to the db responses const createCollection = <T = DocumentData>(collectionName: string) => { return collection(firestore, collectionName) as CollectionReference<T> }
Довольно просто. Довольно лаконично.
Теперь мы импортируем все наши типы из любого места, где они определены, и экспортируем набор констант, запускающих функцию createCollection
, с правильным путем и типом коллекции:
// Get the imports import { initializeApp } from 'firebase/app' import { getFirestore, CollectionReference, collection, DocumentData } from 'firebase/firestore' // Init the firebase app export const firebaseApp = initializeApp({ apiKey: '### FIREBASE API KEY ###', authDomain: '### FIREBASE AUTH DOMAIN ###', projectId: '### CLOUD FIRESTORE PROJECT ID ###' }) // Export firestore incase we need to access it directly export const firestore = getFirestore() // This is just a helper to add the type to the db responses const createCollection = <T = DocumentData>(collectionName: string) => { return collection(firestore, collectionName) as CollectionReference<T> } // Import all your model types import { User } from 'src/types/User' import { Author } from 'src/types/Author' import { Book } from 'src/types/Book' // export all your collections export const usersCol = createCollection<User>('users') export const authorsCol = createCollection<Author>('authors') export const booksCol = createCollection<Book>('books')
Теперь у вас есть только один список имен коллекций и их типов!
Итак, как мне это использовать?
Ну, это так просто, как кажется! Допустим, мы хотим добавить нового пользователя в базу данных, мы просто импортируем usersCol
из useDb
и используем его в качестве первого аргумента функции Firestore setDoc
:
// /someOtherFile.ts import { doc, setDoc } from '@firebase/firestore' import { usersCol } from './composables/useDb' export const setJamiesUser = async () => { const userRef = doc(usersCol, 'user_12345') await setDoc(userRef, { age: 30, firstName: 'Jamie', lastName: 'Curnow' }) }
Если вы попробуете это сделать, вы увидите, что мы получаем подсказки типов и ошибки компилятора, если мы даем setDoc
неправильный тип данных для пользователя!
Другой пример: получение данных... Допустим, мы хотим получить все документы из коллекции books
в базе данных и console.log()
заголовков каждой книги:
// /anotherFile.ts import { getDocs } from '@firebase/firestore' import { booksCol } from './composables/useDb' export const logBookTitles = async () => { const bookDocs = await getDocs(booksCol) bookDocs.docs.forEach((bookDoc) => { const book = bookDoc.data() console.log(book.title) }) }
Здесь typescript знает, что bookDoc.data()
возвращает объект типа Book
, и позволяет нам записать название книги. 🥳
Использование этого способа также будет работать для глубоко вложенных ключей при обновлении документов, что совершенно потрясающе:
import { doc, updateDoc } from '@firebase/firestore' import { booksCol } from './composables/useDb' export const updateBook = async () => { const bookDocRef = doc(booksCol, 'book_12345') await updateDoc(bookDocRef, { 'meta.created': new Date().toISOString() }) }
В этом примере набирается meta.created
! Удивительно!
Подведение итогов
Это такая приятная функция нового SDK V9 Firestore, и команда Firestore проделала фантастическую работу по ее созданию 🙌.
Если вы хотите увидеть минимальный репозиторий, реализующий этот шаблон, оформите заказ и поставьте звездочку:
Не забудьте немного поаплодировать этой истории, если она показалась вам полезной — ваши аплодисменты заставляют меня публиковать контент и дают мне небольшой стимул писать больше каждый раз, когда я вижу, что что-то выходит!
Поддержите своих создателей!
Если вы нашли эту историю полезной и хотели бы, чтобы я продолжал писать полезный контент, пожалуйста, поддержите меня на Patreon 🤗
Дополнительные материалы на plainenglish.io