TIP
This page mirrors .agents/typescript.md from the repository. Edit it at the source, not here.
TypeScript Conventions
Use this for repo-wide TypeScript structure, import boundaries, and schema placement.
For shared cross-package domain contracts in packages/core, follow Core package patterns.
Shared Schema Pattern
For shared package domains, prefer a small domain module over ad hoc type dumping grounds.
src/<domain>/
constants.ts
types.ts
utils.ts
index.tsFor app-local or slice-local code, keep schemas next to the owning route, feature, or package instead of creating a global type folder.
Schema Placement
- Keep schemas close to the owning slice or package.
- For app-local or package-local schemas, the default pattern is
types/thing.type.ts. - When the same schema, enum, or default is consumed across packages, move it into
packages/coreinstead of recreating literal unions inapps/weborpackages/api.
Example package-local schema:
export const ThingSchema = z.object({ ... });
export type Thing = z.infer<typeof ThingSchema>;Both schema (ThingSchema) and type (Thing) are named exports.
When a schema is shared across package boundaries, export the schema and inferred type from the owning shared module and import that same schema everywhere else.
If the frontend needs labels, options, or defaults for a shared enum, derive them from the shared schema or shared helpers instead of creating a second local union.
Module Resolution
nodenextmodule resolution withallowImportingTsExtensions- Cross-package:
@saasweave/<package>/<subpath> - Intra-package:
#@/alias
lib/ vs utils/
| Directory | Contains |
|---|---|
lib/ | Business logic, library integrations, API clients |
utils/ | Pure stateless helper functions |
In packages/core, keep shared schemas in domain types.ts files and pure domain helpers in utils.ts. Do not move router, DB, or React logic there.
Linting (Oxlint)
Inline disable syntax:
// oxlint-disable-next-line no-console
console.log("debug");
// oxlint-disable-line no-console, no-plusplus
console.log(x++);
/* oxlint-disable no-console */
// Disables for rest of fileESLint-style comments (eslint-disable-*) also work for compatibility.
Import Sorting (auto-enforced by Oxfmt)
Order: builtins → external → @saasweave/* → @/pages → @/widgets → @/features → @/shared → relative → styles