xerrion/typescript-rules icon
public
Published on 4/16/2025
TypeScript Rules

Rules
typescript-rules
# TypeScript Best Practices

## Critical Rules

- Use strict type checking with `"strict": true` in tsconfig.json
- Prefer interfaces over type aliases for object definitions that may be extended
- Always define explicit return types for functions and methods
- Use union types instead of enums for simple flag values
- Leverage discriminated unions for complex state management
- Never use `any` type - use `unknown` for truly unknown types
- Always handle null and undefined cases explicitly
- Use readonly modifiers for immutable properties and arrays
- Implement error handling with custom error types
- Use type guards for runtime type checking
- Keep generics simple and well-constrained
- Use Pick, Omit, Partial and other utility types when appropriate
- Document complex types and ALL public functions classes and interfaces with JSDoc comments

## Examples

<example>
// Good - Using interface with explicit types
interface UserState {
  readonly id: string;
  name: string;
  email: string | null;
  preferences: ReadonlyArray<string>;
}

// Good - Discriminated union with type guard
interface RequestPending {
  status: 'pending';
}

interface RequestSuccess {
  status: 'success';
  data: UserState;
}

interface RequestError {
  status: 'error';
  error: Error;
}

type RequestState = RequestPending | RequestSuccess | RequestError;

function isSuccess(state: RequestState): state is RequestSuccess {
  return state.status === 'success';
}

// Good - Generic with constraints
function getProperty<T, K extends keyof T>(obj: T, key: K): T[K] {
  return obj[key];
}
</example>

<example type="invalid">
// Bad - Using any type
function processData(data: any) {
  return data.someProperty;
}

// Bad - Not handling null case
function getUserName(user: { name: string | null }): string {
  return user.name.toUpperCase(); // Might crash
}

// Bad - Using type assertion without checking
function processResponse(response: unknown) {
  const data = response as { id: number };
  return data.id;
}

// Bad - Mutable array without type safety
const items = [];
items.push(123);
items.push('string'); // Mixed types array
</example>