Typesaurus Documentation
website·Indexed 31 days ago
https://typesaurus.comA type-safe wrapper for Firestore that ensures database consistency and provides a seamless API for reading, writing, and real-time updates. Features include first-class support for React and Preact, batch writes, transactions, and advanced schema design tools to secure Firestore databases with full type safety.
What's inside Typesaurus
- Typesaurus provides type-safety for Firestore databases to ensure 100% data consistency. It achieves this by treating document IDs as distinct types, preventing the accidental mixing of different ID types (e.g., preventing a user ID from being used where an account ID is expected). Additionally, Typesaurus validates writes at the type-level to prevent documents from entering inconsistent states.
Implement type-safety and typed IDs in Firestore
Typesaurus enhances Firestore's schema-less nature by providing advanced type-safety that accounts for Firestore-specific nuances (such as server dates and the conversion of undefined to null). Additionally, it implements typed document IDs to prevent bugs and provide self-documenting static or shared IDs.Use SubscriptionPromise to read documents or subscribe to updates
TheSubscriptionPromiseclass is returned by all reading operations. It implements the Promise interface, allowing it to be used withawait,.then(), or.catch(). It supports two mutually exclusive modes: Promise mode (one-time read) and Subscription mode (real-time updates).// Initialize the operation (no request is sent to the DB yet) const sp = db.users.get(userId); // Option 1: Read document once const doc = await sp; // Option 2: Subscribe to updates sp.on((doc) => { console.log('Document updated:', doc); });Use the Doc class to manage database documents
TheDocclass represents a document in the database and is returned from reading operations or created via a collection. It serves as a wrapper that provides access to both the document's reference (metadata/ID) and its actual data, along with methods for reading and writing.import { schema } from "typesaurus"; const db = schema({ users: collection<User>("users"), posts: collection<Post>("posts"), }); // Retrieve a Doc instance const doc = await db.users.get(db.users.id("00sHm46UWKObv2W7XK9e")); // => Doc<User> // Access the ID via the ref property console.log(doc.ref.id); // => "00sHm46UWKObv2W7XK9e" // Access the document data console.log(doc.data); // => UserImplement type-safe IDs for database collections
Typesaurus ensures that IDs are typed based on their collection path to prevent bugs caused by mixing IDs from different entities (e.g., using an account ID where a user ID is expected). By default, a collection ID is linked to its path. For example, a user collection ID is typed asId<"users">and a subcollection ID is typed asId<"users/reports">.import { schema } from "typesaurus"; const db = schema(($) => ({ users: $.collection<User>(), accounts: $.collection<Account>().sub({ reports: $.collection<Report>(), }), })); // TypeScript will prevent this: db.users.update(accountId, { name: "Sasha" }); // Error: Argument of type 'Id<"accounts">' is not assignable to parameter of type 'Id<"users">'.Handle undefined values in Typesaurus models
Because Firestore does not support
undefinedvalues and throws runtime errors when they are encountered, Typesaurus automatically replaces allundefinedvalues withnullacross both objects and arrays. This ensures consistent behavior and prevents runtime crashes regardless of the TypeScript configuration.Since data retrieved from Typesaurus may contain
nullwhere the original model definedundefined(or optional properties), you must account fornullwhen consuming the data.Access and use Collection Groups with the Group class
TheGroupclass represents a collection group in the database. You access these groups using thegroups(db)function. This allows you to target all collections sharing the same name across different paths in your schema.interface Comment { text: string; } const db = schema(($) => ({ users: $.collection<User>().sub({ posts: $.collection<UserPost>().sub({ comments: $.collection<Comment>(), }), }), posts: $.collection<Post>().sub({ comments: $.collection<Comment>(), }), })); // Accesses all 'comments' collections across the database const commentsGroup = groups(db).comments; // => Group<Comment>Handle Firestore data types with Typesaurus
Typesaurus simplifies Firestore data handling by automatically converting Firestore timestamps into native JavaScriptDateinstances. It also preserves document references andundefinedvalues, ensuring a more JavaScript-native experience.Understand Typesaurus architectural principles and design philosophy
Typesaurus is designed to provide complete type-safety for reading from and writing to Firestore to prevent bugs and preserve data consistency. The architecture prioritizes the following values in order of importance:
- Safety guards: The type system is designed to prevent developers from making mistakes.
- Error clarity: Errors are intended to guide developers or be thoroughly documented.
- Simplicity: The resulting code is kept as simple as possible without compromising typings.
Typesaurus adopts a "TypeScript-first" approach, meaning that if a trade-off must be made between API ease-of-use and the quality of the TypeScript types, the type system takes precedence to ensure the best possible experience for TypeScript developers.
Ensure Firestore data consistency with Typesaurus type-safety
Typesaurus provides type-safety for Firestore databases to ensure data consistency. It achieves this by treating document IDs as distinct types, which prevents the accidental mixing of different ID types (e.g., preventing a user ID from being used where an account ID is expected). Additionally, it performs type-level validation on writes to prevent documents from entering inconsistent states.Ensure Firestore data consistency with Typesaurus type-safety
Typesaurus provides type-safety for Firestore databases to ensure 100% data consistency. It achieves this by treating document IDs as distinct types, which prevents the accidental mixing of different ID types (e.g., preventing a user ID from being used where an account ID is expected). Additionally, Typesaurus validates writes at the type-level to prevent documents from entering inconsistent states.Prevent data inconsistency with Typesaurus Safe Paths
Typesaurus implements 'safe paths' to prevent partial updates that would leave a document in an impossible state. If you attempt to update a specific field within an optional nested object (e.g.,$.field("address", "street")), Typesaurus may throw a type error (often appearing asnever) if that update would result in the parent object missing other required fields defined in the interface. This ensures that if a nested object exists, it always conforms to its full type definition.