mcpField
T
typescript-conventions

typescript-conventions

github.com/exceptionlessDevelopment2.5k48 installsUpdated today
Repository

About typescript-conventions

A TypeScript conventions skill that helps coding agents follow project rules for formatting, naming, imports, and type safety. It also covers promise handling, control flow, and exports.

Key features

  1. 01Follow formatting and minimal-diff rules
  2. 02Define file naming and import practices
  3. 03Emphasize type safety and avoid any
  4. 04Require deliberate promise handling
  5. 05Standardize control flow and exports

Use cases

  1. 01Guide TypeScript code changes
  2. 02Check consistency of names and imports
  3. 03Shape type definitions and error handling
  4. 04Standardize asynchronous code and exports

Install

Copy the command and run it in a terminal.

$npx skills add https://github.com/exceptionless/exceptionless --skill typescript-conventions

After installing, type/typescript-conventionsin Claude Code to confirm it loaded.

Details

From the project README

TypeScript Conventions

Style & Formatting

  • Follow .editorconfig and ESLint + Prettier config strictly
  • Run npm run format before committing
  • Minimize diffs: Change only what's necessary, preserve existing formatting and structure
  • Match surrounding code style exactly

Project Frontend Rules

  • Always use braces for all control flow statements (if, for, while, etc.).
  • Always use block bodies for arrow functions that return statements; avoid single-expression shorthand in project code.
  • Do not use abbreviations in identifiers (organization, not org; filter, not filt).
  • Avoid inline single-line condition + return patterns; use multi-line blocks for readability.

File Naming

  • Use kebab-case for files and directories
  • Component files: user-profile.svelte
  • TypeScript files: api-client.ts, user-service.ts
  • Test files: user-service.test.ts or user-service.spec.ts

Imports

Prefer Named Imports
// ✅ Good: Named imports
import { UserService, type User } from "$lib/services/user-service";
import { formatDate, formatNumber } from "$lib/utils/formatters";

// ❌ Avoid: Namespace imports (except allowed exceptions)
import * as utils from "$lib/utils";
  • Named imports are preferred for most modules; namespace imports should be limited to approved patterns (e.g., shadcn composite imports).
Allowed Namespace Imports
// ✅ Allowed: shadcn-svelte components
import * as Dialog from "$comp/ui/dialog";
import * as DropdownMenu from "$comp/ui/dropdown-menu";

// ✅ Allowed: Barrel exports
import * as Field from "$comp/ui/field";

Type Safety

Avoid any
// ❌ Bad
function processData(data: any) { ... }

// ✅ Good: Use interfaces/types
interface UserData {
    id: string;
    name: string;
    email: string;
}

function processData(data: UserData) { ... }

// ✅ Good: Use unknown for truly unknown data
function parseResponse(data: unknown): UserData {
    if (isUserData(data)) {
        return data;
    }
    throw new Error('Invalid data format');
}
Type Guards
function isUserData(data: unknown): data is UserData {
    return (
        typeof data === "object" &&
        data !== null &&
        "id" in data &&
        "name" in data &&
        "email" in data
    );
}

// Discriminated unions
type ApiResponse =
    | { status: "success"; data: UserData }
    | { status: "error"; error: string };

function handleResponse(response: ApiResponse) {
    if (response.status === "success") {
        // TypeScript knows response.data exists
        return response.data;
    }
    // TypeScript knows response.error exists
    throw new Error(response.error);
}

Promise Handling

Always Await
// ✅ Good: Always await
const user = await fetchUser(id);
const [users, projects] = await Promise.all([fetchUsers(), fetchProjects()]);

// ❌ Bad: Fire and forget without handling
fetchUser(id); // Exception is lost!
Error Handling
// ✅ Good: try/catch with proper typing
async function loadUser(id: string): Promise<User | null> {
    try {
        const response = await api.get<User>(`/users/${id}`);
        return response.data;
    } catch (error) {
        if (error instanceof ApiError) {
            console.error("API Error:", error.message);
        }
        return null;
    }
}

Control Statements

All single-line control statements need braces:

// ✅ Good: Always use braces
if (condition) {
    doSomething();
}

for (const item of items) {
    process(item);
}

// ❌ Bad: No braces
if (condition) doSomething();

Interface Naming

Follow HTTP verb prefixes for API-related types:

// Request/Response interfaces
interface PostOrganizationRequest {
    name: string;
    billing_email: string;
}

interface GetOrganizationParams {
    id: string;
}

interface PatchUserRequest {
    name?: string;
    email?: string;
}

Export Patterns

// Named exports preferred
export function createUser(data: CreateUserRequest): Promise<User> { ... }
export type { User, CreateUserRequest };

// Re-export from barrel files
// src/lib/features/users/index.ts
export { createUser, updateUser, deleteUser } from './api.svelte';
export type { User, CreateUserRequest } from './models';

Modern ES6+ Features

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

// Destructuring
const { id, name, email } = user;
const [first, ...rest] = items;

// Nullish coalescing
const displayName = user.nickname ?? user.name ?? "Anonymous";

// Optional chaining
const city = user?.address?.city;

// Object shorthand
const data = { id, name, createdAt: new Date() };

Comments

Markdown supported