Claude Skill

typescript

Patterns and conventions for all TypeScript code. Use this skill whenever writing or reviewing TypeScript, naming identifiers, typing exports, choosing between type and interface, using Zod schemas, structuring function parameters, or enforcing code patterns like avoiding switch

LLM Mart · 0 points · 16 views 0 listing impressions 0 install-command copies
Virus-scanned Reviewed automatically before listing.

Full trust report

Download gaia-react-gaia-.claude_skills_typescript-6bb0226.zip · 5 KB
Part of gaia-react/gaia — 26 skills

Install

skills CLI npx skills add https://github.com/gaia-react/gaia/tree/main/.claude/skills/typescript
Claude Code claude plugin marketplace add https://llmmart.ai/marketplace.json && claude plugin install gaia-react-gaia@llmmart
Git git clone https://github.com/gaia-react/gaia.git

The skills CLI installs just this skill, for any of its supported agents. Claude Code installs the whole gaia-react/gaia collection as a plugin from our marketplace. Git is the plain clone.

Skill manifest

TypeScript

Patterns and conventions for all TypeScript code.

Types

  • import type {} for type-only imports: import type {FC} from 'react'

Naming, camelCase

All identifiers use camelCase: Zod fields, form name/id/htmlFor, props, state, params.

Exceptions (snake_case OK):

  • types/database.ts, mirrors DB column names
  • Dynamic template literal names where variable part is already lowercase
  • Environment variable names (SUPABASE_URL)

Map snake_case ↔ camelCase at API call boundaries, not in schemas or UI code.

Naming, Descriptive and Self-Documenting

Follow Apple's Swift API Design Guidelines: names should be clear at the point of use, reading like prose. Favor long, descriptive names over short or abbreviated ones. Code should be readable without consulting documentation.

  • Functions and methods: imperative verb phrases: calculateProgressPercentageFromCompletedSets, processUserOnboardingProfile
  • Parameters: role, not type: totalSeconds not n, emailAddress not s
  • Variables: what they hold: restDurationInSeconds, submitButton, weightInputValue
  • No abbreviations: spell out unless universally known (url, id, api): animationDurationInMilliseconds not animDur
  • No redundant words: availableExercises not exerciseArray, but don't sacrifice clarity for brevity

Exception, React event handlers follow handle{Action}{Element} from the react-code skill (e.g. handleClickSave, handleChangeInput), the {Element} is required, since a bare handleClick or handleChange trips react-doctor/no-generic-handler-names. The descriptive naming guidelines above apply to utilities, hooks, callbacks, and non-event-handler functions.

Read references/naming-conventions.md for extended BAD/GOOD examples of each naming pattern.

Exported Functions, Explicit Return Types

All exported functions must have explicit return types.

Exceptions:

  • Route loaders/actions (complex generics)
  • React components typed with FC<Props> (return type provided by generic)
// BAD
export const formatDate = (date: Date) => format(date, 'yyyy-MM-dd');

// GOOD
export const formatDate = (date: Date): string => format(date, 'yyyy-MM-dd');

General Rules

  • Use type not interface, interfaces support declaration merging, which creates unpredictable behavior; type is consistent and predictable
  • Arrays: string[] not Array<string>
  • Boolean naming: ^((can|has|hide|is|show)[A-Z]|checked|disabled|required)

Code Patterns

  • No switch statements, use if/else chains or object maps; switch requires break, is prone to fallthrough bugs, and is harder to type-check exhaustively
  • No TypeScript enums, use as const objects with derived types; enums compile to runtime objects with surprising behavior and don't tree-shake well
  • JSX boolean props: always explicit ={true}, makes props grep-able and avoids confusion when a prop is later refactored to a non-boolean type
  • Max 3 function parameters, use an options object beyond that; call sites with 4+ positional args are hard to read and argument order mistakes are common
  • Inline boolean coercion uses !!x, never Boolean(x); reserve Boolean for point-free use (e.g. array.filter(Boolean)), and coerce per operand in a nullable || chain (!!a || !!b), since !!(a || b) trips @typescript-eslint/prefer-nullish-coalescing
  • Prefer undefined over null for GAIA-controlled absence (state, optional fields, internal sentinels); reserve null for external contracts that require it: DOM useRef(null), ref-callback params, React Router data(null), Zod .nullable(), and platform/library APIs that return null

Zod

This project uses Zod 4, in every schema. The deprecated Zod 3 chained forms (.strict(), .email(), single-arg z.record(), .args().returns()) still type-check and lint clean, so nothing flags them, reach for the Zod 4 form deliberately.

  • z.literal([...]) not z.enum() for string unions, sort values alphanumerically

Read references/zod.md for the full Zod 3 → Zod 4 migration map (z.strictObject, top-level string formats, z.record arity, function and error shapes). It opens with a standing directive to verify uncertain or suspect Zod forms against the official docs (WebFetched, auto-discovered from node_modules/zod/package.json) rather than trusting v3-era memory.

Files (gaia)
  • references
    • naming-conventions.md 2.5 KB
      # Naming Conventions, Extended Examples
      
      ## Functions and Methods
      
      Read like imperative verb phrases that describe what they do and what they act on.
      
      ```ts
      // BAD, vague, what does "handle" mean? what is "data"?
      const handle = (data: unknown) => { ... }
      const proc = (u: User) => { ... }
      const calc = (a: number, b: number) => { ... }
      
      // GOOD, clear intent at every call site
      const handleWorkoutSessionTimeout = (session: WorkoutSession) => { ... }
      const processUserOnboardingProfile = (user: User) => { ... }
      const calculateProgressPercentageFromCompletedSets = (completedSets: number, totalSets: number) => { ... }
      ```
      
      > React event handlers are the exception (`handle{Action}{Element}`); see the event-handler note in `typescript/SKILL.md`. The descriptive guidelines above apply to utilities, hooks, callbacks, and non-event-handler functions.
      
      ## Parameters and Arguments
      
      Named for their role, not their type.
      
      ```ts
      // BAD, type as name, single-letter params
      const formatDuration = (n: number): string => { ... }
      const findUser = (s: string): User | null => { ... }
      
      // GOOD, role is immediately clear
      const formatDurationInSeconds = (totalSeconds: number): string => { ... }
      const findUserByEmailAddress = (emailAddress: string): User | null => { ... }
      ```
      
      ## Variables and Constants
      
      Describe what they hold, not how they're used.
      
      ```ts
      // BAD, abbreviations, vague names
      const btn = document.querySelector('button');
      const val = form.get('weight');
      const temp = calculateRestDuration();
      const MAX = 3;
      
      // GOOD, unambiguous at a glance
      const submitButton = document.querySelector('button');
      const weightInputValue = form.get('weight');
      const restDurationInSeconds = calculateRestDuration();
      const maximumRetryAttemptCount = 3;
      ```
      
      ## Avoiding Abbreviations
      
      Spell out words in full unless the abbreviation is universally known (e.g., `url`, `id`, `api`).
      
      ```ts
      // BAD
      const calcBMI = (ht: number, wt: number) => { ... }
      const usrPref = getUserPref();
      const animDur = 300;
      
      // GOOD
      const calculateBodyMassIndex = (heightInCentimeters: number, weightInKilograms: number) => { ... }
      const userDisplayPreferences = getUserDisplayPreferences();
      const animationDurationInMilliseconds = 300;
      ```
      
      ## Omitting Redundant Words
      
      Don't pad names with type noise, but don't sacrifice readability for brevity.
      
      ```ts
      // BAD, redundant type noise
      const exerciseArray = getExercises();
      const userObject = fetchUser();
      
      // BAD, too terse
      const ex = getExercises();
      const u = fetchUser();
      
      // GOOD, just right
      const availableExercises = getExercises();
      const currentUser = fetchUser();
      ```
      
    • zod.md 4.5 KB
      # Zod 4, Zod 3 → Zod 4 Migration Map
      
      ## Authoritative source, consult before judging a schema
      
      Zod 4 reworked the API heavily from v3, and most v3 forms still type-check, so training memory is an unreliable guide here: it is easy to "correct" valid v4 code back into deprecated v3 code, or to reject a valid form as invalid. The array union `z.literal(['a', 'b'])` in the migration map below is real Zod 4, not a mistake. So before writing a schema you are unsure of, and especially before flagging or rewriting an existing Zod form as wrong, verify it against the installed Zod's official docs and treat them as authoritative over memory.
      
      The docs are hosted, and the package advertises their URLs through the `package.json` auto-discovery convention. Read the URL from the installed package rather than hardcoding it:
      
      ```bash
      node -p "require('./node_modules/zod/package.json').llmsFull"  # https://zod.dev/llms-full.txt, full concatenated docs
      node -p "require('./node_modules/zod/package.json').llms"      # https://zod.dev/llms.txt, curated index
      ```
      
      WebFetch that URL with a specific question instead of reading it into context. The full doc is ~65k tokens, but WebFetch distills it through a side model and returns only the answer, so context pays for the answer, not the doc. Ask for the exact signature and request a verbatim quote (e.g. "quote the exact `z.literal` signature for multiple values"). When the topic is unclear, WebFetch the smaller index first to find the right page. If the fields are absent, fall back to `https://zod.dev/llms-full.txt`.
      
      Version caveat: these hosted docs track the latest published Zod, not the installed one, so confirm the installed major matches before trusting them with `node -p "require('./node_modules/zod/package.json').version"`. If the project is ever pinned behind what zod.dev serves, the docs run ahead of the installed API and the memory-versus-reality problem returns.
      
      ## Migration map
      
      This project uses Zod 4; default to the Zod 4 form in every schema.
      
      | Zod 3, avoid                             | Zod 4, use                            |
      | ---------------------------------------- | ------------------------------------- |
      | `z.object({…}).strict()`                 | `z.strictObject({…})`                 |
      | `z.object({…}).passthrough()`            | `z.looseObject({…})`                  |
      | `z.record(z.string())`                   | `z.record(z.string(), z.string())`    |
      | `z.string().email()`                     | `z.email()`                           |
      | `z.string().url()`                       | `z.url()`                             |
      | `z.string().uuid()`                      | `z.uuid()`                            |
      | `z.string().datetime()`                  | `z.iso.datetime()`                    |
      | `z.enum(['metric', 'imperial'])`         | `z.literal(['imperial', 'metric'])`, values sorted alphanumerically (`z.enum()` is valid Zod 4, but the project standardizes on the literal-array form) |
      | `z.function().args(a).returns(b)`        | `z.function({input: [a], output: b})` |
      | `z.string({required_error: 'Required'})` | `z.string({error: 'Required'})`       |
      
      ## Strict objects
      
      `.strict()` / `.passthrough()` / `.strip()` are deprecated methods. Use the top-level factories.
      
      ```ts
      // BAD, Zod 3 chained method
      const Payload = z.object({id: z.string(), tags: z.array(z.string())}).strict();
      
      // GOOD, Zod 4 factory
      const Payload = z.strictObject({id: z.string(), tags: z.array(z.string())});
      ```
      
      ## String formats
      
      Format validators moved from `ZodString` methods to top-level functions (`z.iso.*` for ISO date/time).
      
      ```ts
      // BAD
      z.object({email: z.string().email(), createdAt: z.string().datetime()});
      
      // GOOD
      z.object({email: z.email(), createdAt: z.iso.datetime()});
      ```
      
      ## Records
      
      Both key and value schemas are required, single-arg `z.record()` is Zod 3.
      
      ```ts
      // BAD
      z.record(z.number());
      
      // GOOD
      z.record(z.string(), z.number());
      ```
      
      ## Functions
      
      `.args()` / `.returns()` chaining is replaced by an `{input, output}` object; `input` is the array of argument schemas.
      
      ```ts
      // BAD
      const fn = z.function().args(z.string(), z.number()).returns(z.boolean());
      
      // GOOD
      const fn = z.function({input: [z.string(), z.number()], output: z.boolean()});
      ```
      
      ## Error customization
      
      The unified `error` key replaces `message`, `required_error`, `invalid_type_error`, and `errorMap`.
      
      ```ts
      // BAD
      z.string({required_error: 'Required', invalid_type_error: 'Must be text'});
      z.string().min(5, {message: 'Too short'});
      
      // GOOD
      z.string({error: 'Required'});
      z.string().min(5, {error: 'Too short'});
      ```
      
  • SKILL.md 4.7 KB
    ---
    name: typescript
    description: Patterns and conventions for all TypeScript code. Use this skill whenever writing or reviewing TypeScript, naming identifiers, typing exports, choosing between type and interface, using Zod schemas, structuring function parameters, or enforcing code patterns like avoiding switch statements and enums.
    model: haiku
    ---
    
    # TypeScript
    
    Patterns and conventions for all TypeScript code.
    
    ## Types
    
    - `import type {}` for type-only imports: `import type {FC} from 'react'`
    
    ## Naming, camelCase
    
    All identifiers use camelCase: Zod fields, form `name`/`id`/`htmlFor`, props, state, params.
    
    **Exceptions (snake_case OK):**
    
    - `types/database.ts`, mirrors DB column names
    - Dynamic template literal names where variable part is already lowercase
    - Environment variable names (`SUPABASE_URL`)
    
    Map snake_case ↔ camelCase at API call boundaries, not in schemas or UI code.
    
    ## Naming, Descriptive and Self-Documenting
    
    Follow Apple's Swift API Design Guidelines: names should be clear at the point of use, reading like prose. Favor long, descriptive names over short or abbreviated ones. Code should be readable without consulting documentation.
    
    - **Functions and methods**: imperative verb phrases: `calculateProgressPercentageFromCompletedSets`, `processUserOnboardingProfile`
    - **Parameters**: role, not type: `totalSeconds` not `n`, `emailAddress` not `s`
    - **Variables**: what they hold: `restDurationInSeconds`, `submitButton`, `weightInputValue`
    - **No abbreviations**: spell out unless universally known (`url`, `id`, `api`): `animationDurationInMilliseconds` not `animDur`
    - **No redundant words**: `availableExercises` not `exerciseArray`, but don't sacrifice clarity for brevity
    
    > **Exception, React event handlers** follow `handle{Action}{Element}` from the react-code skill
    > (e.g. `handleClickSave`, `handleChangeInput`), the `{Element}` is required, since a bare
    > `handleClick` or `handleChange` trips `react-doctor/no-generic-handler-names`. The descriptive
    > naming guidelines above apply to utilities, hooks, callbacks, and non-event-handler functions.
    
    Read `references/naming-conventions.md` for extended BAD/GOOD examples of each naming pattern.
    
    ## Exported Functions, Explicit Return Types
    
    All exported functions must have explicit return types.
    
    **Exceptions:**
    
    - Route loaders/actions (complex generics)
    - React components typed with `FC<Props>` (return type provided by generic)
    
    ```tsx
    // BAD
    export const formatDate = (date: Date) => format(date, 'yyyy-MM-dd');
    
    // GOOD
    export const formatDate = (date: Date): string => format(date, 'yyyy-MM-dd');
    ```
    
    ## General Rules
    
    - Use `type` not `interface`, interfaces support declaration merging, which creates unpredictable behavior; `type` is consistent and predictable
    - Arrays: `string[]` not `Array<string>`
    - Boolean naming: `^((can|has|hide|is|show)[A-Z]|checked|disabled|required)`
    
    ## Code Patterns
    
    - No `switch` statements, use if/else chains or object maps; switch requires `break`, is prone to fallthrough bugs, and is harder to type-check exhaustively
    - No TypeScript enums, use `as const` objects with derived types; enums compile to runtime objects with surprising behavior and don't tree-shake well
    - JSX boolean props: always explicit `={true}`, makes props grep-able and avoids confusion when a prop is later refactored to a non-boolean type
    - Max 3 function parameters, use an options object beyond that; call sites with 4+ positional args are hard to read and argument order mistakes are common
    - Inline boolean coercion uses `!!x`, never `Boolean(x)`; reserve `Boolean` for point-free use (e.g. `array.filter(Boolean)`), and coerce per operand in a nullable `||` chain (`!!a || !!b`), since `!!(a || b)` trips `@typescript-eslint/prefer-nullish-coalescing`
    - Prefer `undefined` over `null` for GAIA-controlled absence (state, optional fields, internal sentinels); reserve `null` for external contracts that require it: DOM `useRef(null)`, ref-callback params, React Router `data(null)`, Zod `.nullable()`, and platform/library APIs that return `null`
    
    ## Zod
    
    **This project uses Zod 4**, in every schema. The deprecated Zod 3 chained forms (`.strict()`, `.email()`, single-arg `z.record()`, `.args().returns()`) still type-check and lint clean, so nothing flags them, reach for the Zod 4 form deliberately.
    
    - **`z.literal([...])` not `z.enum()`** for string unions, sort values alphanumerically
    
    Read `references/zod.md` for the full Zod 3 → Zod 4 migration map (`z.strictObject`, top-level string formats, `z.record` arity, function and error shapes). It opens with a standing directive to verify uncertain or suspect Zod forms against the official docs (WebFetched, auto-discovered from `node_modules/zod/package.json`) rather than trusting v3-era memory.
    

Comments (0)

Sign in to join the conversation.

No comments yet.

Reviews (0)

No reviews yet.

Related