Skip to content

Use TypeScript as Intended ​

TypeScript was created to help developers write safer and more maintainable JavaScript. It enforces static typing, catches errors earlier, improves IDE support, and documents intent directly in code. To fully benefit from it, avoid shortcuts and use TypeScript's advanced features as they were designed.

Key practices ​

  • any is prohibited. Use unknown at boundaries, then narrow it down.
  • Prefer type for unions/mapped types; interface for extensible object shapes.
  • Use generics with constraints and defaults. Extract generic helpers instead of duplication.
  • Use literal unions or enum for closed sets. Centralize labels and helpers.
  • Enforce exhaustiveness with never in discriminated unions.

Discriminated unions ​

ts
type ApiResponse =
  | { status: "success"; data: string }
  | { status: "error"; message: string };

function handleResponse(res: ApiResponse) {
  switch (res.status) {
    case "success":
      return res.data;
    case "error":
      return res.message;
    default:
      const _exhaustive: never = res;
      return _exhaustive;
  }
}

typeof keyword ​

ts
const ROLES = ["admin", "editor", "viewer"] as const;
type Role = typeof ROLES[number]; // "admin" | "editor" | "viewer"

function setRole(role: Role) {
  // role is strictly validated
}

Generics and wildcards ​

ts
interface BaseResponse<T> {
  status: number;
  data: T;
}

function fetchResource<T>(url: string): Promise<BaseResponse<T>> {
  return fetch(url).then((res) => res.json());
}

// Usage
type User = { id: number; name: string };
const userResponse = fetchResource<User>("/api/user");