typescript-conventions
TypeScript coding standards for the Exceptionless frontend. Naming, imports, error handling, ESLint/Prettier configuration, and type safety. Keywords: TypeScript, ESLint, Prettier, naming conventions, kebab-case, named imports, type guards, interfaces, avoid any, Promise handling, try catch, braces
Installation
Follow the repository instructions for this skill and your agent. Review the files and dependencies before adding it to your workflow.
View source ↗GuidesSkill instructions
TypeScript Conventions
Style & Formatting
- Follow
.editorconfigand ESLint + Prettier config strictly - Run
npm run formatbefore committing - Minimize diffs: Change only what's necessary, preserve existing formatting and structure
- Match surrounding code style exactly
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.tsoruser-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';
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() };
Examples
Read the usage examples in the source repository.
View source ↗Source history
- Indexed on
- 2026-01-20
- Index updated
- 2026-01-26
- Branch
- main
Index and sync dates describe this directory. View the source repository for code history.
GitHub ↗chat Comments (0)
Sign in to join the discussion and leave a comment.
No comments yet. Be the first to share your thoughts!