Setting up Types
To get the most out of pb-query, you should define TypeScript types that reflect your PocketBase collections. This allows pb-query to provide type safety and autocompletion based on your schema.
Define Your Types
Create TypeScript interfaces for each of your PocketBase collections. Make sure to include all the fields you plan to use in your queries.
export interface User {
id: string;
name: string;
email: string;
created: Date;
updated: Date;
}
export interface Post {
id: string;
title: string;
content: string;
author: User; // relation
status: 'draft' | 'published';
created: Date;
updated: Date;
}
Supported Field Types
| PocketBase Field | TypeScript Type |
|---|---|
| Plain text, Rich editor, Email, URL | string |
| Number | number |
| Bool | boolean |
| Datetime, Autodate | Date |
| JSON | object, Array<T>, or custom type |
| Geo Point | Use the GeoPoint exposed by pb-query |
| Relation | Your collection interface ( e.g. User) |
| Multi-valued Fields (multiple relation, multiple select, or multiple file) | Array of the required type ( e.g. string[], User[] ) |
| Select | Union of string literals ( e.g. 'draft' | 'published') |
When you use a value of the wrong type in your query, TypeScript will raise an error, helping you catch mistakes early.
const query = pbQuery<Post>()
.between('created', new Date('2023-01-01'), new Date('2023-12-31')); // ✅ Correct
const query = pbQuery<Post>()
.equal('created', '@today'); // ✅ Correct
const query = pbQuery<Post>()
.equal('created', '2025'); // ❌ TypeScript Error
Using Types with pbQuery
When building queries, make sure to specify the type of the collection you are querying.
const { filter, sort } = pbQuery<Post>() // posts collection
.search(['title', 'content', 'author.name'], 'footba')
.and()
.group((q) =>
q.equal('status', 'published')
.or()
.equal('author.name', 'Sergio')
)
.sort(['-created'])
.build(pb.filter);
const { filter, sort } = pbQuery<User>() // users collection
.like('name', 'Sergio')
.build(pb.filter);
Integration with Pocketbase Typegen
If you're already using Pocketbase Typegen you can reuse the generated types with pb-query. However, they need some adjustments.
Pocketbase Typegen produces:
RecordIdStringfor relations.IsoDateStringfor date fields.
These types are string-based, so pb-query can't infer relations or dates.
Recommended adjustments
- Replace
RecordIdStringwith the actual relation type. This is required, if you don't, you won't get type-checking for nested fields likeauthor.name. - Replace
IsoDateStringwithDate(optional, but recommended).
import type { PostsRecord, UsersRecord } from './types-from-pocketbase-typegen'
type UsersQuery = Omit<UsersRecord, 'created' | 'updated'> & {
created: Date;
updated: Date;
};
type PostsQuery = Omit<PostsRecord, 'author' | 'created' | 'updated'> & {
author: UsersQuery;
created: Date;
updated: Date;
};
import type { PostsRecord, UsersRecord } from './types-from-pocketbase-typegen'
type UsersQuery = UsersRecord;
type PostsQuery = Omit<PostsRecord, 'author'> & {
author: UsersQuery;
};
*Record like PostsRecord. However, if you need to access additional fields like collectionId inside .fields(), you can use PostsResponse instead.Back-relations
Currently, pb-query doesn't have enough context to support back-relations properly. It would need to know a lot more about the collection schema, which complicates things quite a bit. We're working on proper back-relation support. Follow #12 for updates.
For now, you can use back-relation fields containing _via_, but they bypass type-checking:
const { filter } = pbQuery<User>()
.like('posts_via_author.name', 'Sergio') // ⚠️ No type-checked
.build(pb.filter);
posts_via_author.titel won't be caught by TypeScript.