TypeScript Coding Standards#

Reference#

Type Annotations#

  1. Basic Types - Be explicit when TypeScript can’t infer - Use built-in types appropriately - Avoid any

// ❌ Bad
let value: any;
const numbers = [];

// ✅ Good
let value: string;
const numbers: number[] = [];
const handler = (event: React.MouseEvent) => {};
  1. React Props - Define prop interfaces - Use children prop when needed - Document complex props

interface ButtonProps {
  variant: 'primary' | 'secondary';
  onClick: () => void;
  children: React.ReactNode;
}

Interfaces vs. Type Aliases#

  1. Use Interfaces For - React components props - Objects with clear contracts - Extendable shapes

// ✅ Good for interfaces
interface UserProfile {
  id: string;
  name: string;
}

interface AdminProfile extends UserProfile {
  permissions: string[];
}
  1. Use Types For - Unions and intersections - Complex types - Function types

// ✅ Good for type aliases
type ButtonVariant = 'primary' | 'secondary';
type Handler = (event: MouseEvent) => void;
type Theme = 'light' | 'dark';

Generics#

  1. Common Use Cases - Reusable components - Type-safe functions - API responses

// Generic component
interface ListProps<T> {
  items: T[];
  renderItem: (item: T) => React.ReactNode;
}

// Generic function
const getFirstItem = <T>(array: T[]): T => array[0];

Type Definitions for External Libraries#

  1. Module Declarations - Declare modules for CSS - Add missing library types - Extend existing types

// CSS Modules
declare module '*.module.css' {
  const classes: { [key: string]: string };
  export default classes;
}

// Extend Window
declare global {
  interface Window {
    customProperty: string;
  }
}
  1. Library Types - Install @types packages - Create custom declarations - Document type extensions

Enums vs. Union Types#

  1. Union Types (Preferred) - Use for simple choices - String literals for values - Better tree-shaking

// ❌ Avoid enums
enum ButtonSize {
  Small = 'small',
  Large = 'large'
}

// ✅ Use union types
type ButtonSize = 'small' | 'large';
type Theme = 'light' | 'dark';
  1. When to Use Enums - Fixed set of values - Numeric values needed - Backend compatibility

Linting and Formatting#

  1. TSConfig

{
  "compilerOptions": {
    "strict": true,
    "noImplicitAny": true,
    "strictNullChecks": true,
    "jsx": "react"
  }
}
  1. ESLint Rules

module.exports = {
  extends: [
    'plugin:@typescript-eslint/recommended',
    'plugin:react/recommended'
  ],
  rules: {
    '@typescript-eslint/explicit-function-return-type': 'off',
    '@typescript-eslint/no-unused-vars': 'error'
  }
};

CSS Module Types#

  1. Module Declaration - Ensure type safety for CSS Modules - Enable autocomplete - Prevent typos

// styles.d.ts
declare module '*.module.css' {
  const classes: {
    readonly [key: string]: string;
  };
  export default classes;
}
  1. Usage with Components

import styles from './Button.module.css';

interface ButtonProps {
  className?: string;
  variant: keyof typeof styles;
}

const Button: React.FC<ButtonProps> = ({
  variant,
  className
}) => (
  <button className={`${styles[variant]} ${className}`}>
    Click me
  </button>
);