TypeScript type definitions for Firebase Firestore providing comprehensive type safety for database operations
—
Pending
Does it follow best practices?
Impact
Pending
No eval scenarios have been run
Pending
The risk profile of this skill
Types for collection references, query building, and query result handling including filtering, ordering, and pagination.
Reference to a Firestore collection, extending Query with collection-specific operations.
class CollectionReference<T = DocumentData, T2 extends DocumentData = DocumentData> extends Query<T, T2> {
private constructor();
/** Collection ID */
readonly id: string;
/** Parent document reference, or null for root collections */
readonly parent: DocumentReference<DocumentData> | null;
/** Full collection path */
readonly path: string;
/** Get a document reference in this collection */
doc(documentPath?: string): DocumentReference<T>;
/** Add a new document to this collection */
add(data: T): Promise<DocumentReference<T>>;
/** Check if this reference equals another */
isEqual(other: CollectionReference<T>): boolean;
/** Convert this reference to use a different data type */
withConverter(converter: null): CollectionReference<DocumentData>;
withConverter<U>(
converter: FirestoreDataConverter<U>
): CollectionReference<U>;
}Base class for building and executing Firestore queries.
class Query<T = DocumentData, T2 extends DocumentData = DocumentData> {
protected constructor();
/** Firestore instance this query belongs to */
readonly firestore: FirebaseFirestore;
/** Filter documents where field matches condition */
where(
fieldPath: string | FieldPath,
opStr: WhereFilterOp,
value: any
): Query<T>;
/** Order results by field */
orderBy(
fieldPath: string | FieldPath,
directionStr?: OrderByDirection
): Query<T>;
/** Limit number of results */
limit(limit: number): Query<T>;
/** Limit to last N results (requires orderBy) */
limitToLast(limit: number): Query<T>;
/** Start results at document snapshot */
startAt(snapshot: DocumentSnapshot<any>): Query<T>;
/** Start results at field values */
startAt(...fieldValues: any[]): Query<T>;
/** Start results after document snapshot */
startAfter(snapshot: DocumentSnapshot<any>): Query<T>;
/** Start results after field values */
startAfter(...fieldValues: any[]): Query<T>;
/** End results before document snapshot */
endBefore(snapshot: DocumentSnapshot<any>): Query<T>;
/** End results before field values */
endBefore(...fieldValues: any[]): Query<T>;
/** End results at document snapshot */
endAt(snapshot: DocumentSnapshot<any>): Query<T>;
/** End results at field values */
endAt(...fieldValues: any[]): Query<T>;
/** Check if this query equals another */
isEqual(other: Query<T>): boolean;
/** Execute query and get results */
get(options?: GetOptions): Promise<QuerySnapshot<T>>;
/** Listen for query result changes */
onSnapshot(observer: {
next?: (snapshot: QuerySnapshot<T>) => void;
error?: (error: FirestoreError) => void;
complete?: () => void;
}): () => void;
onSnapshot(
options: SnapshotListenOptions,
observer: {
next?: (snapshot: QuerySnapshot<T>) => void;
error?: (error: FirestoreError) => void;
complete?: () => void;
}
): () => void;
onSnapshot(
onNext: (snapshot: QuerySnapshot<T>) => void,
onError?: (error: FirestoreError) => void,
onCompletion?: () => void
): () => void;
onSnapshot(
options: SnapshotListenOptions,
onNext: (snapshot: QuerySnapshot<T>) => void,
onError?: (error: FirestoreError) => void,
onCompletion?: () => void
): () => void;
/** Convert this query to use a different data type */
withConverter(converter: null): Query<DocumentData>;
withConverter<U>(converter: FirestoreDataConverter<U>): Query<U>;
}type OrderByDirection = 'desc' | 'asc';
type WhereFilterOp =
| '<' // Less than
| '<=' // Less than or equal
| '==' // Equal to
| '!=' // Not equal to
| '>=' // Greater than or equal
| '>' // Greater than
| 'array-contains' // Array contains value
| 'in' // Field value in array
| 'array-contains-any' // Array contains any of the values
| 'not-in'; // Field value not in arrayType-safe field path construction for nested fields.
class FieldPath {
/** Create a field path from field names */
constructor(...fieldNames: string[]);
/** Special field path representing document ID */
static documentId(): FieldPath;
/** Check if this field path equals another */
isEqual(other: FieldPath): boolean;
}import type { CollectionReference, DocumentData } from "@firebase/firestore-types";
interface User {
name: string;
email: string;
age: number;
}
async function manageCollection(collection: CollectionReference<User>) {
// Add new document with auto-generated ID
const docRef = await collection.add({
name: "Alice",
email: "alice@example.com",
age: 30
});
// Get specific document reference
const specificDoc = collection.doc("user-123");
// Get all documents in collection
const snapshot = await collection.get();
snapshot.forEach(doc => {
const userData = doc.data(); // Typed as User
console.log('User:', userData.name);
});
}import type { Query, WhereFilterOp, OrderByDirection } from "@firebase/firestore-types";
function buildQueries(usersCollection: CollectionReference<User>) {
// Simple where clause
const adults = usersCollection.where("age", ">=", 18);
// Multiple filters
const activeAdults = usersCollection
.where("age", ">=", 18)
.where("status", "==", "active");
// Array queries
const usersInCities = usersCollection
.where("city", "in", ["New York", "San Francisco", "Seattle"]);
// Ordering and limiting
const topUsers = usersCollection
.orderBy("score", "desc")
.limit(10);
// Pagination with cursors
const paginatedQuery = usersCollection
.orderBy("createdAt")
.startAfter(lastDocSnapshot)
.limit(20);
return { adults, activeAdults, usersInCities, topUsers, paginatedQuery };
}import type { FieldPath } from "@firebase/firestore-types";
interface UserProfile {
basic: {
name: string;
email: string;
};
preferences: {
theme: string;
notifications: boolean;
};
}
function queryNestedFields(collection: CollectionReference<UserProfile>) {
// Query nested field using dot notation
const darkThemeUsers = collection.where("preferences.theme", "==", "dark");
// Query nested field using FieldPath
const notificationUsers = collection.where(
new FieldPath("preferences", "notifications"),
"==",
true
);
// Order by nested field
const orderedByName = collection.orderBy("basic.name");
return { darkThemeUsers, notificationUsers, orderedByName };
}import type { QuerySnapshot, DocumentChange } from "@firebase/firestore-types";
function listenToQuery(query: Query<User>) {
const unsubscribe = query.onSnapshot({
next: (snapshot: QuerySnapshot<User>) => {
console.log(`Query returned ${snapshot.size} documents`);
// Process changes
const changes = snapshot.docChanges();
changes.forEach((change: DocumentChange<User>) => {
const userData = change.doc.data();
switch (change.type) {
case 'added':
console.log('New user:', userData.name);
break;
case 'modified':
console.log('Modified user:', userData.name);
break;
case 'removed':
console.log('Removed user:', userData.name);
break;
}
});
},
error: (error) => {
console.error('Query error:', error);
}
});
return unsubscribe;
}