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, untyped props:import { track } from '@syntarie/tracking';track('checkout_compleded', { plan: 'pro' });// ^^^^^^^^^^^^^^^^^^ typo, accepted at compile time, drops at the collector
// 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 — 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 lives in tooling/codegen/. From the repo root:
pnpm codegenThis:
- Reads
shared/tracking-plan/schema.yaml(or whatever path you configure). - Validates the plan against the canonical tracking-plan schema.
- Emits
sdk/src/generated/events.tswith one overload per event.
You should run codegen as a prebuild step in CI so 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.