Agent Skills: TypeScript Guidelines

TypeScript code style, type co-location, naming conventions (including acronym casing), test organization, and arktype patterns. Use when writing TypeScript code, defining types, naming variables/functions, organizing tests, or working with arktype schemas.

UncategorizedID: epicenterhq/epicenter/typescript

Repository

EpicenterHQLicense: AGPL-3.0
4,024273

Install this agent skill to your local

pnpm dlx add-skill https://github.com/EpicenterHQ/epicenter/tree/HEAD/.agents/skills/typescript

Skill Files

Browse the full folder contents for typescript.

Download Skill

Loading file tree…

.agents/skills/typescript/SKILL.md

Skill Metadata

Name
typescript
Description
'TypeScript project conventions: derived types, type placement, acronym casing, imports, generics, factories, and runtime schema patterns. Use when editing `.ts` files, defining exported types, reviewing type names, or organizing type tests.'

TypeScript Guidelines

Use this skill for project-wide TypeScript conventions before loading narrower skills such as arktype, typebox, testing, or method-shorthand-jsdoc.

When To Apply This Skill

Use this skill when you need to:

  • Write or refactor TypeScript with Epicenter naming and style conventions.
  • Decide whether to derive, import, or declare a type.
  • Review type ownership, copied shapes, factory return types, brands, casts, and generic names.
  • Choose clear value-mapping and control-flow patterns for unions and discriminated values.
  • Organize type tests, runtime schemas, or factory-focused refactors.

Core Rules

  • Try to derive or import a type before declaring a new named type. New named types must earn their place as a real contract, protocol vocabulary, discriminated result union, capability port, or multi-implementation shape.
  • Treat local shape copies as boundary smells. Prefer the owning runtime type, schema inference, factory return type, function signature, or a caller-owned capability function.
  • Use type, not interface.
  • Use readonly only for arrays and maps, unless matching an upstream type exactly.
  • Treat acronyms as normal words in camelCase: parseUrl, defineKv, readJson, customerId.
  • Use .js extensions in relative imports. Do not use extensionless or .ts relative imports.
  • Export symbols at their declarations. Reserve export { ... } from ... for barrel files.
  • Prefer factory functions over classes. Let closure position communicate private vs public API.
  • Use descriptive generic names with a T prefix, such as TSchema, TDefs, and TKey.
  • Destructure options in the function signature when the object is a configuration bag. Keep a named value only when it is the domain object being transformed or forwarded.
  • Let TypeScript infer private and inner return types. Annotate exported APIs only when useful for clarity or to break circular inference.
  • If an exported type is exactly the object returned by a create* factory, derive it with ReturnType<typeof createThing>. Put useful annotations on returned members instead of duplicating the object shape.
  • Use a Symbol brand when identity means a specific factory output, not a coincidental shape probe.
  • Avoid as any. Use unknown, validation, brands, or narrower helpers instead.
  • Prefer optional chaining over in checks or truthiness when checking optional properties.
  • Use is, has, or can prefixes for booleans that answer a question.
  • Prefer switch over if/else for repeated equality comparisons against the same value. Use default: value satisfies never for exhaustiveness when needed.
  • Prefer Record lookup tables over nested ternaries for finite value mappings.
  • Compose typed errors bottom-up. Do not filter a broad upstream error union at the boundary.
  • Question silent fallbacks that hide invalid state. Preserve round-trip invariants when parsing and serializing.

Go-to-Definition Awareness

When organizing types and exports, always consider Go-to-Definition. A developer pressing Go-to-Def from a call site should land as close as possible to the actual source of truth. If a design choice forces an extra navigation hop, the choice has to earn it elsewhere (e.g., a real validation boundary, a published contract, or a multi-implementation port).

Concrete regressions to watch for:

  • Destructure-re-export of a module-level object: const stub = { fn, gn } satisfies T; export const { fn, gn } = stub; lands Go-to-Def on the destructuring line, not the real definition. Prefer per-export satisfies or a direct export const fn = ... satisfies T['fn'].
  • typeof Real annotation over satisfies: export const fn: typeof Real = unreachable hides the underlying value's identity from navigation. export const fn = unreachable satisfies typeof Real keeps the value as the source of truth.
  • Re-export chains in non-barrel files: export { X } from './alias' outside index.ts costs an extra hop with nothing to show for it. Reserve export { ... } from ... for barrels; export at the declaration everywhere else.
  • Adapter / proxy / wrapper with no behavior change: a fromX translator or thin passthrough makes Go-to-Def land on the wrapper. Widen the underlying factory's return shape instead (see factory-function-composition "collapsed adapter" rule).
  • Manual return type annotation duplicating zone 4: annotating a factory with a hand-written interface diverts Go-to-Def to the alias. Use ReturnType<typeof createThing> so navigation lands on the actual returned member (this is the same choice that drives JSDoc preservation, see method-shorthand-jsdoc).

For broader public-shape decisions that affect navigation across packages, see cohesive-clean-breaks.

Reference Map

  • Project conventions: detailed examples for derived types, local shape copies, imports, barrels, factories, generics, destructuring, and factory return types.
  • Type safety and control flow: identity brands, casts, optional properties, boolean naming, switches, record lookups, error composition, fallback smells, and round-trip invariants.
  • Type organization: types.ts location, co-location rules, inline-vs-extract hop test, options and ID naming.
  • Factory patterns: factory-focused refactors, parameter destructuring, and coupled state extraction.
  • Runtime schema patterns: arktype, branded IDs, optional property syntax, and workspace table IDs.
  • Testing patterns: inline single-use setup and source-shadowing tests.
  • Advanced TypeScript features: iterator helpers and const generic array inference.