Skip to content

/standards-typescript

This skill provides TypeScript coding standards and is automatically loaded for TypeScript projects. It includes naming conventions, best practices, and recommended tooling.

From plugin
5711 skills12 commands1 hooks
shell
$ npx -y skills add b33eep/claude-code-setup --skill standards-typescript --agent claude-code

How it fires

How this skill gets triggered: by you, by Claude, or both.

  • Fires itselfAuto-invocation. Claude auto-loads it when your prompt matches the work.
  • You can call itInvoke it directly when you want it.
  • Slash command/standards-typescript
How auto-invocation works

Context preview

The summary Claude sees to decide when to auto-load this skill.

This skill provides TypeScript coding standards and is automatically loaded for TypeScript projects. It includes naming conventions, best practices, and recommended tooling.

SKILL.md

standards-typescript.SKILL.md
name: standards-typescript
description: This skill provides TypeScript coding standards and is automatically loaded for TypeScript projects. It includes naming conventions, best practices, and recommended tooling.
type: context
applies_to: [typescript, nodejs, express, nestjs, nextjs, react, vue, angular, deno, bun, zod]
file_extensions: [".ts", ".tsx", ".jsx"]

TypeScript Coding Standards

Core Principles

1. **Simplicity**: Simple, understandable code 2. **Readability**: Readability over cleverness 3. **Maintainability**: Code that's easy to maintain 4. **Testability**: Code that's easy to test 5. **DRY**: Don't Repeat Yourself - but don't overdo it

General Rules

  • **Early Returns**: Use early returns to avoid nesting
  • **Descriptive Names**: Meaningful names for variables and functions
  • **Minimal Changes**: Only change relevant code parts
  • **No Over-Engineering**: No unnecessary complexity
  • **Minimal Comments**: Code should be self-explanatory. No redundant comments!

Naming Conventions

| Element | Convention | Example | |---------|------------|---------| | Variables/Functions | camelCase | `getUserById`, `isActive` | | Classes/Interfaces/Types | PascalCase | `UserService`, `ApiClient` | | Constants | UPPER_SNAKE_CASE | `MAX_RETRY_COUNT` | | Private | Prefix with `_` or `#` | `_internalMethod`, `#privateField` | | Files | kebab-case or camelCase | `user-service.ts`, `userService.ts` | | Interfaces | No `I` prefix | `User` not `IUser` | | Type aliases | PascalCase | `UserId`, `HttpMethod` | | Event Handlers | Prefix with `handle` | `handleClick`, `handleSubmit` |

Project Structure

myproject/
├── src/
│   ├── index.ts              # Entry point
│   ├── config.ts             # Settings, env vars
│   ├── types/
│   │   └── index.ts          # Shared types
│   ├── models/
│   │   └── user.ts           # Domain models
│   ├── services/
│   │   └── user-service.ts   # Business logic
│   ├── repositories/
│   │   └── user-repo.ts      # Data access
│   └── utils/
│       └── helpers.ts        # Utility functions
├── tests/
│   ├── services/
│   │   └── user-service.test.ts
│   └── setup.ts
├── package.json
├── tsconfig.json
└── README.md

Code Style

// Use explicit types for function parameters and return values
function getUserById(userId: string): User | undefined {
  if (!userId) {
    throw new Error("userId cannot be empty");
  }
  // implementation...
}

// Prefer interfaces for object shapes
interface User {
  id: string;
  name: string;
  email: string;
  age?: number;
}

// Use type aliases for unions, intersections, or primitives
type UserId = string;
type HttpMethod = "GET" | "POST" | "PUT" | "DELETE";
type Result<T> = { success: true; data: T } | { success: false; error: string };

Best Practices

// Prefer const over let
const users: User[] = [];

// Use nullish coalescing and optional chaining
const name = user?.profile?.name ?? "Anonymous";

// Prefer template literals
const message = `Hello, ${user.name}!`;

// Use destructuring
const { id, name, email } = user;
function processUser({ id, name }: User): void { }

// Prefer array methods over loops
const activeUsers = users.filter(u => u.isActive);
const userNames = users.map(u => u.name);
const totalAge = users.reduce((sum, u) => sum + u.age, 0);

// Use readonly for immutable data
interface Config {
  readonly apiUrl: string;
  readonly maxRetries: number;
}

// Use as const for literal types
const DIRECTIONS = ["north", "south", "east", "west"] as const;
type Direction = typeof DIRECTIONS[number];

// Prefer unknown over any
function parseJson(input: string): unknown {
  return JSON.parse(input);
}

// Type guards for type narrowing
function isUser(value: unknown): value is User {
  return typeof value === "object" && value !== null && "id" in value;
}

Utility Types

// Partial<T> - Make all properties optional
type UserUpdate = Partial<User>;
// { id?: string; name?: string; email?: string; age?: number }

// Pick<T, K> - Select specific properties
type UserPreview = Pick<User, "id" | "name">;
// { id: string; name: string }

// Omit<T, K> - Exclude specific properties
type UserWithoutEmail = Omit<User, "email">;
// { id: string; name: string; age?: number }

// Record<K, T> - Object with specific keys and value type
type RolePermissions = Record<"admin" | "user" | "guest", string[]>;
// { admin: string[]; user: string[]; guest: string[] }

// ReturnType<F> - Extract return type of function
type FetchResult = ReturnType<typeof fetchUser>;
// Promise<User | undefined>

// Parameters<F> - Extract parameter types
type FetchParams = Parameters<typeof fetchUser>;
// [userId: string]

// Awaited<T> - Unwrap Promise type
type ResolvedUser = Awaited<ReturnType<typeof fetchUser>>;
// User | undefined

Discriminated Unions

// Use a common "type" or "status" field as discriminator
type ApiResponse<T> =
  | { status: "success"; data: T }
  | { status: "error"; error: string }
  | { status: "loading" };

function handleResponse(response: ApiResponse<User>) {
  switch (response.status) {
    case "success":
      console.log(response.data.name); // TypeScript knows data exists
      break;
    case "error":
      console.error(response.error); // TypeScript knows error exists
      break;
    case "loading":
      console.log("Loading...");
      break;
  }
}

// State machines with discriminated unions
type AuthState =
  | { state: "idle" }
  | { state: "loading" }
  | { state: "authenticated"; user: User }
  | { state: "error"; message: string };

// Action types for reducers
type UserAction =
  | { type: "SET_USER"; payload: User }
  | { type: "CLEAR_USER" }
  | { type: "UPDATE_NAME"; payload: string };

Runtime Validation with Zod

import { z } from "zod";

// Define schema
const UserSchema = z.object({
  id: z.string().uuid(),
  name: z.string().min(1).max(100),
  email: z.string().email(),
Read more
Read it on GitHub ↗

Showing the first part of this file.

Ships withclaude-code-setup

Persistent memory for Claude Code via Markdown files. 📖 Read the Documentation for detailed guides, tutorials, and reference.

Get the whole plugin, auto-invoked
Stats
57
Stars
0
Views
6
Forks
Maintained
Maintenance
Shell
Language
MIT
License
2mo ago
Last commit
6mo ago
Created

Repo: b33eep/claude-code-setup