Guides
Working With Types

Working with Types

Typing the queues and handlers will help prevent you from misusing Sidetrack, like inserting a job on a nonexistent queue, or inserting a job with an invalid payload. Following the types will improve your developer experience.

To get started, pass in the type for Sidetrack's constructor. This type is an object with keys that match your queue names, and values that are the type of the payload for that queue. For example, if you have a queue called userOnboarding, and the payload is an object with an email property, you can type your queues like this:

ts
type QueueNamesAndPayloads = {
userOnboarding: { email: string };
};
ts
type QueueNamesAndPayloads = {
userOnboarding: { email: string };
};

The type of your payload must only use JSON serializable values, since the job payload will be persisted in the DB as JSONB.

Here is the full example:

ts
import { Sidetrack } from "sidetrack";
 
type QueueNamesAndPayloads = {
userOnboarding: { email: string };
};
 
const sidetrack = new Sidetrack<QueueNamesAndPayloads>({
databaseOptions: {
connectionString: process.env["DATABASE_URL"]!,
},
queues: {
userOnboarding: {
handler: async (job) => {
console.log(`Welcome ${job.payload.email}`);
},
},
},
});
ts
import { Sidetrack } from "sidetrack";
 
type QueueNamesAndPayloads = {
userOnboarding: { email: string };
};
 
const sidetrack = new Sidetrack<QueueNamesAndPayloads>({
databaseOptions: {
connectionString: process.env["DATABASE_URL"]!,
},
queues: {
userOnboarding: {
handler: async (job) => {
console.log(`Welcome ${job.payload.email}`);
},
},
},
});

Notice how the handler function receives a job. This job contains a payload key which will be typed to match your payload types above. The job also contains other fields you can use in your handler function (e.g. the job's id, scheduledAt, status, currentAttempt, etc.)

Avoiding errors

You can insert a job on only the userOnboarding queue. Notice the type error if I try inserting on a queue that doesn't exist.

ts
sidetrack.insertJob("reports", { email: "a@example.com" });
Argument of type '"reports"' is not assignable to parameter of type '"userOnboarding"'.2345Argument of type '"reports"' is not assignable to parameter of type '"userOnboarding"'.
ts
sidetrack.insertJob("reports", { email: "a@example.com" });
Argument of type '"reports"' is not assignable to parameter of type '"userOnboarding"'.2345Argument of type '"reports"' is not assignable to parameter of type '"userOnboarding"'.

Types also prevent you from inserting a job with incorrect payload. Notice I must pass a email of type string.

ts
sidetrack.insertJob("userOnboarding", { phone: "11111111111" });
Object literal may only specify known properties, and 'phone' does not exist in type '{ email: string; }'.2353Object literal may only specify known properties, and 'phone' does not exist in type '{ email: string; }'.
ts
sidetrack.insertJob("userOnboarding", { phone: "11111111111" });
Object literal may only specify known properties, and 'phone' does not exist in type '{ email: string; }'.2353Object literal may only specify known properties, and 'phone' does not exist in type '{ email: string; }'.

Reusable Types

Sidetrack exports most of the types it uses internally, so you can easily type your handlers and queues. For example, if you have a queue called userOnboarding, you can type your handler like this:

ts
import { Sidetrack, SidetrackQueues } from "sidetrack";
 
type QueueNamesAndPayloads = {
userOnboarding: { email: string };
};
 
const queues: SidetrackQueues<QueueNamesAndPayloads> = {
userOnboarding: {
handler: async (job) => {
console.log(`Welcome ${job.payload.email}`);
},
},
};
 
const sidetrack = new Sidetrack<QueueNamesAndPayloads>({
databaseOptions: {
connectionString: process.env["DATABASE_URL"]!,
},
queues,
});
ts
import { Sidetrack, SidetrackQueues } from "sidetrack";
 
type QueueNamesAndPayloads = {
userOnboarding: { email: string };
};
 
const queues: SidetrackQueues<QueueNamesAndPayloads> = {
userOnboarding: {
handler: async (job) => {
console.log(`Welcome ${job.payload.email}`);
},
},
};
 
const sidetrack = new Sidetrack<QueueNamesAndPayloads>({
databaseOptions: {
connectionString: process.env["DATABASE_URL"]!,
},
queues,
});

Notice how the SidetrackQueues helper type lets you type your queues before you pass them in to the constructor, so you can also re-use them.