TypeScript codegen
@syntarie/tracking/generated/events is a generated file: the codegen tool
reads your tracking plan and emits a typed track() whose name argument is
narrowed to your registered event names and whose props argument is
narrowed to the per-event interface.
Why use it
Section titled “Why use it”// Without codegen, string literals and untyped props:import { track } from '@syntarie/tracking';track('checkout_compleded', { plan: 'pro' });// ^^^^^^^^^^^^^^^^^^ typo, accepted at compile time, dropped on ingest
// With codegen, names and props checked at compile time:import { track } from '@syntarie/tracking/generated/events';track('checkout_compleded', { plan: 'pro' });// ~~~~~~~~~~~~~~~~~~~~ Type error: argument of type "checkout_compleded"// is not assignable to parameter of type// TrackedEventName.Behind the scenes the runtime function is the same untyped track. The
generated subpath only adds compile-time overloads, so there is no runtime
overhead and no extra bytes shipped if you import only from the generated
path.
Run codegen
Section titled “Run codegen”The codegen CLI ships with @syntarie/tracking. Point it at your tracking
plan and an output path:
pnpm exec leadmaps-codegen --plan ./tracking-plan.yaml --out ./src/generated/events.tsThis:
- Reads your tracking-plan YAML.
- Validates the plan against the tracking-plan schema.
- Emits a typed-
track()module with one overload per event.
Run codegen as a prebuild step in CI so the generated output never drifts
from the source plan.
What it emits
Section titled “What it emits”For a plan event like:
checkout_completed: description: User finished checkout and a payment intent succeeded. owner: ecommerce classification: revenue props: type: object required: [order_id, total_cents, currency] additionalProperties: false properties: order_id: { type: string, minLength: 1 } total_cents: { type: integer, minimum: 0 } currency: { type: string, pattern: "^[A-Z]{3}$" } coupon_code: { type: string }The generator emits roughly:
export interface CheckoutCompletedProps { readonly order_id: string; readonly total_cents: number; readonly currency: string; readonly coupon_code?: string;}
export interface TrackedEvents { // ...other events... readonly checkout_completed: CheckoutCompletedProps;}
export type TrackedEventName = keyof TrackedEvents;
export function track<N extends TrackedEventName>( name: N, props: TrackedEvents[N],): void;Extending the registry
Section titled “Extending the registry”You can extend TrackedEvents via TypeScript declaration merging if you
need to track an event before it lands in the central plan:
declare module '@syntarie/tracking/generated/events' { interface TrackedEvents { readonly experimental_event: { readonly variant: string }; }}The runtime path is unchanged. The merge only adds a compile-time narrowing for that name.
Versioning
Section titled “Versioning”Adding a new event to the plan and re-running codegen is a minor bump
of @syntarie/tracking (a new key on TrackedEvents). Removing an event
inside a major is forbidden by the semver policy.
See Versioning §1.2.