TypeScript

The Inngest SDK leverages the full power of TypeScript, providing you with some awesome benefits when handling events:

  • 📑 Autocomplete
    Tab ↹ your way to victory with inferred types for every event.
  • Instant feedback
    Understand exactly where your code might error before you even save the file.

All of this comes together to provide some awesome type inference based on your actual production data.

Using types

Once your types are generated, there are a few ways we can use them to ensure our functions are protected.

new Inngest() client

We can use these when creating a new Inngest client via new Inngest().

This comes with powerful inference; we autocomplete your event names when selecting what to react to, without you having to dig for the name and data.

inngest/client.ts

import { EventSchemas, Inngest } from "inngest";

type UserSignup = {
  data: {
    email: string;
    name: string;
  };
};
type Events = {
  "user/new.signup": UserSignup;
};

export const inngest = new Inngest({
  id: "my-app",
  schemas: new EventSchemas().fromRecord<Events>(),
});

inngest/sendWelcomeEmail.ts

import { inngest } from "./client";

export default inngest.createFunction(
  { id: "send-welcome-email" },
  { event: "user/new.signup" },
  async ({ event }) => {
    // "event" is fully typed to provide typesafety within this function
    return await email.send("welcome", event.data.email);
  }
);

Sending events

TypeScript will also enforce your custom events being the right shape - see Event Format for more details.

We recommend putting your new Inngest() client and types in a single file, i.e. /inngest/client.ts so you can use it anywhere that you send an event.

Here's an example of sending an event within a Next.js API handler:

pages/api/signup.ts

import type { NextApiRequest, NextApiResponse } from "next";
import { inngest } from "../../inngest/client";

export default function handler(req: NextApiRequest, res: NextApiResponse) {
  const user = createNewUser(req.body.email, req.body.password, req.body.name);

  // TypeScript will now warn you if types do not match for the event payload
  // and the user object's properties:
  await inngest.send({
    name: "user/new.signup",
    data: {
      email: user.email,
      name: user.name,
    }
  });
  res.status(200).json({ success: true });
}

Using with waitForEvent

When writing step functions, you can use waitForEvent to to, pause the current function until another event is received or the timeout expires - whichever happens first. When you declare your types using the Inngest constructor, waitForEvent leverages any types that you have:

inngest/client.ts

import { EventSchemas, Inngest } from "inngest";

type UserSignup = {
  data: {
    email: string;
    user_id: string;
    name: string;
  };
};
type UserAccountSetupCompleted = {
  data: {
    user_id: string;
  };
};
type Events = {
  "user/new.signup": UserSignup;
  "user/account.setup.completed": UserAccountSetupCompleted;
};

export const inngest = new Inngest({
  id: "my-app",
  schemas: new EventSchemas().fromRecord<Events>(),
});

inngest/onboardingDripCampaign.ts

import { inngest } from "./client";

export default inngest.createFunction(
  { id: "onboarding-drip-campaign" },
  { event: "user/new.signup" },
  async ({ event, step }) => {
    await step.run("send-welcome-email", async () => {
      // "event" will be fully typed provide typesafety within this function
      return await email.send("welcome", event.data.email);
    });

    // We wait up to 2 days for the user to set up their account
    const accountSetupCompleted = await step.waitForEvent(
      "wait-for-setup-complete",
      {
        event: "user/account.setup.completed",
        timeout: "2d",
        // ⬇️ This matches both events using the same property
        // Since both events types are registered above, this is match is typesafe
        match: "data.user_id",
      }
    );

    if (!accountSetupCompleted) {
      await step.run("send-setup-account-guide", async () => {
        return await email.send("account_setup_guide", event.data.email);
      });
    }
  }
);