Blob: types/AGENTS.md
types/
OVERVIEW
Generates @cloudflare/workers-types .d.ts files from C++ RTTI (via jsg/rtti.capnp) + hand-written defines/*.d.ts. A workerd-hosted Worker extracts RTTI at runtime per compat-date; TypeScript transforms post-process into ambient and importable outputs. CI validates generated-snapshot/ matches.
PIPELINE
- RTTI extraction:
src/worker/runs inside workerd, imports binary RTTI viaworkerd:rtti+ param names fromparam-extractor.rs - Generation:
src/generator/converts Cap'n Proto structures to TS AST nodes (walks types, members, methods recursively viacollectIncluded) - Transforms (ordered, in
src/index.ts): iterators -> overrides/defines -> global scope extraction -> class-to-interface -> comments -> onmessage declaration; then second pass: import-resolve -> ambient. Importable variant runs separately. - Defines concatenation:
defines/*.d.tsappended after transforms (AI, D1, R2, RPC, Vectorize, etc.) - Build:
scripts/build-types.tsiterates compat-date entrypoints (oldest through experimental), type-checks output against TS libs
KEY DIRECTORIES
| Directory | Purpose |
|---|---|
src/generator/ |
RTTI-to-TS-AST: structure.ts (classes/interfaces), type.ts (type mapping) |
src/transforms/ |
11 post-processing TS transformer factories |
src/worker/ |
Workerd-hosted entry; imports RTTI binary + virtual modules |
defines/ |
Hand-written .d.ts for APIs not expressible via C++ RTTI (~25 files) |
generated-snapshot/ |
Checked-in latest/ + experimental/ output; CI diff-checked |
scripts/ |
build-types.ts (full generation), build-worker.ts (worker bundle) |
test/ |
Vitest specs for generator, transforms, print; type-check tests in test/types/ |
ADDING OR UPDATING TYPES
Where type changes belong
Types in this project come from three layers. Changes must be made in the correct layer:
| Layer | Location | When to use |
|---|---|---|
| C++ RTTI | src/workerd/api/*.h (JSG macros) |
Types derived from C++ classes — the generator extracts these automatically |
JSG_TS_OVERRIDE |
Same .h files, inside JSG_RESOURCE_TYPE blocks |
When the auto-generated TS signature needs adjustment (e.g., conditional properties, union narrowing) |
| Hand-written defines | types/defines/*.d.ts |
Types for APIs not expressible via C++ RTTI (Cloudflare product bindings like AI, D1, R2, Vectorize, etc.) |
Do not edit files in generated-snapshot/ directly — they are overwritten by just generate-types. If the generated output looks wrong, fix the source layer (C++ RTTI, JSG_TS_OVERRIDE, or defines/).
Naming conventions
Types in defines/*.d.ts become top-level ambient declarations visible to every Worker project. Generic names will collide or confuse.
- Prefix types with the product or feature name. For example:
D1Meta,AiSearchConfig,VectorizeVector— notMeta,Config, orVector. - Follow the existing convention for the relevant product. Check the existing
defines/file for that product (e.g.,cf.d.tsusesIncomingRequestCfProperties*,d1.d.tsusesD1*,ai-search.d.tsusesAiSearch*). - When in doubt, be more specific. A name like
TracePreviewInfois better thanPreview. The cost of a verbose name is low; the cost of a naming collision in every user's project is high.
Interface design
- Never use bare
objectas a type.type Foo = objectprevents all property access without casting, providing no value to users. Use a proper interface with known fields instead. - Use interfaces with known fields + index signature for types where the shape is partially known but extensible. Follow the
IncomingRequestCfPropertiesBasepattern:interface CloudflareAccessIdentity extends Record<string, unknown> { email?: string; name?: string; // ... other known fields } - Index signatures (
[key: string]: unknown) need justification. Only add them when forward-compatibility is genuinely required (e.g., the API frequently adds new fields across releases). Document the reason in a JSDoc comment. Do not add index signatures by default. - Add JSDoc comments to interfaces and their fields, especially for types used in
defines/. These comments appear in users' IDEs.
Snapshot regeneration
After any change that affects types (C++ API changes, JSG_TS_OVERRIDE edits, defines/ modifications), regenerate the snapshot:
just generate-typesCI will fail if generated-snapshot/ does not match the generated output. Always commit the updated snapshot alongside your source changes.
Type tests
Type-level tests live in test/types/ (e.g., test/types/rpc.ts). These are compile-time checks — they verify that type expressions are accepted or rejected by the TypeScript compiler.
- When adding new types or changing existing ones, add or update type tests to cover the new shapes.
- Review type test changes carefully — a test that compiles successfully may still be asserting the wrong thing.
PR hygiene for type changes
- Do not include unrelated formatting changes in PRs that modify types. If formatting needs fixing, do it in a separate commit or PR.
- Type changes in feature PRs need review from someone familiar with the types system. The Wrangler team typically reviews type changes that affect
@cloudflare/workers-types.