Documentation
TypeScript
Configuration

TypeScript Configuration

Strict TypeScript setup for React projects.

tsconfig.json

{
  "compilerOptions": {
    // Target
    "target": "ES2022",
    "lib": ["ES2022", "DOM", "DOM.Iterable"],
    "module": "ESNext",
    "moduleResolution": "bundler",
    "jsx": "react-jsx",
 
    // Strict mode
    "strict": true,
    "noUncheckedIndexedAccess": true,
    "noImplicitReturns": true,
    "noFallthroughCasesInSwitch": true,
    "noUnusedLocals": true,
    "noUnusedParameters": true,
    "exactOptionalPropertyTypes": true,
 
    // Module handling
    "esModuleInterop": true,
    "allowSyntheticDefaultImports": true,
    "forceConsistentCasingInFileNames": true,
    "resolveJsonModule": true,
    "isolatedModules": true,
 
    // Emit
    "noEmit": true,
    "skipLibCheck": true,
 
    // Path aliases
    "baseUrl": ".",
    "paths": {
      "@/*": ["./src/*"]
    }
  },
  "include": ["src/**/*"],
  "exclude": ["node_modules", "dist"]
}

Key Options Explained

Strict Mode Options

OptionPurpose
strictEnables all strict type-checking options
noUncheckedIndexedAccessAdds undefined to index access types
noImplicitReturnsAll code paths must return a value
noFallthroughCasesInSwitchNo fallthrough in switch statements
noUnusedLocalsError on unused local variables
noUnusedParametersError on unused parameters
exactOptionalPropertyTypesDifferentiate undefined and optional

noUncheckedIndexedAccess Example

const users: User[] = [];
 
// Without noUncheckedIndexedAccess
const user = users[0]; // type: User ❌
 
// With noUncheckedIndexedAccess
const user = users[0]; // type: User | undefined ✅
 
// Forces you to handle undefined
if (user) {
  console.log(user.name);
}

exactOptionalPropertyTypes Example

interface Config {
  timeout?: number;
}
 
// Without exactOptionalPropertyTypes
const config: Config = { timeout: undefined }; // ✅ Allowed
 
// With exactOptionalPropertyTypes
const config: Config = { timeout: undefined }; // ❌ Error
const config: Config = {}; // ✅ Correct

Vite Configuration

// vite.config.ts
import { defineConfig } from 'vite';
import react from '@vitejs/plugin-react';
import path from 'path';
 
export default defineConfig({
  plugins: [react()],
  resolve: {
    alias: {
      '@': path.resolve(__dirname, './src'),
    },
  },
});

ESLint TypeScript Rules

// eslint.config.js
export default {
  rules: {
    '@typescript-eslint/no-unused-vars': [
      'error',
      { argsIgnorePattern: '^_' },
    ],
    '@typescript-eslint/no-explicit-any': 'error',
    '@typescript-eslint/consistent-type-imports': [
      'error',
      { prefer: 'type-imports' },
    ],
    '@typescript-eslint/no-non-null-assertion': 'warn',
    '@typescript-eslint/prefer-nullish-coalescing': 'error',
    '@typescript-eslint/prefer-optional-chain': 'error',
  },
};

Recommended Extensions

VSCode Settings

{
  "typescript.preferences.importModuleSpecifier": "non-relative",
  "typescript.suggest.autoImports": true,
  "typescript.updateImportsOnFileMove.enabled": "always"
}

Type Checking in CI

# .github/workflows/typecheck.yml
- name: Type Check
  run: pnpm tsc --noEmit