Complete guide to configuring TypeScript projects with optimal tooling and development workflow.
Start by installing TypeScript and creating the necessary configuration files.
# Global installation (for CLI access)
npm install -g typescript
# Project installation (recommended for consistent versions)
npm install --save-dev typescript @types/node
# For React projects
npm install --save-dev @types/react @types/react-dom
# For Node.js projects with additional types
npm install --save-dev @types/express @types/cors @types/jsonwebtoken {
"scripts": {
"build": "tsc",
"build:watch": "tsc --watch",
"dev": "ts-node src/index.ts",
"dev:watch": "ts-node-dev --respawn --transpile-only src/index.ts",
"type-check": "tsc --noEmit",
"lint": "eslint src/**/*.{ts,tsx}",
"lint:fix": "eslint src/**/*.{ts,tsx} --fix",
"test": "jest",
"test:watch": "jest --watch"
},
"devDependencies": {
"typescript": "^5.0.0",
"@types/node": "^18.0.0",
"ts-node": "^10.0.0",
"ts-node-dev": "^2.0.0"
}
} A well-configured tsconfig.json is crucial for type safety and development experience.
{
"compilerOptions": {
// Language and Environment
"target": "ES2022",
"module": "ESNext",
"moduleResolution": "node",
"lib": ["ES2022", "DOM", "DOM.Iterable"],
// Strict Type Checking
"strict": true,
"noImplicitAny": true,
"strictNullChecks": true,
"strictFunctionTypes": true,
"strictBindCallApply": true,
"strictPropertyInitialization": true,
"noImplicitThis": true,
"noImplicitReturns": true,
"noFallthroughCasesInSwitch": true,
"noUncheckedIndexedAccess": true,
"noImplicitOverride": true,
// Module Resolution
"baseUrl": "./",
"paths": {
"@/*": ["src/*"],
"@/components/*": ["src/components/*"],
"@/utils/*": ["src/utils/*"],
"@/types/*": ["src/types/*"]
},
"resolveJsonModule": true,
"allowSyntheticDefaultImports": true,
"esModuleInterop": true,
// Emit
"outDir": "./dist",
"rootDir": "./src",
"removeComments": true,
"declaration": true,
"declarationMap": true,
"sourceMap": true,
"inlineSources": true,
// Interop Constraints
"forceConsistentCasingInFileNames": true,
"allowUnreachableCode": false,
"allowUnusedLabels": false,
// Advanced
"skipLibCheck": true,
"experimentalDecorators": true,
"emitDecoratorMetadata": true
},
"include": [
"src/**/*",
"tests/**/*"
],
"exclude": [
"node_modules",
"dist",
"**/*.js"
]
} Combine TypeScript with ESLint and Prettier for consistent code quality and formatting.
npm install --save-dev eslint @typescript-eslint/parser @typescript-eslint/eslint-plugin eslint-config-prettier {
"env": {
"browser": true,
"es2022": true,
"node": true
},
"extends": [
"eslint:recommended",
"@typescript-eslint/recommended",
"@typescript-eslint/recommended-requiring-type-checking",
"prettier"
],
"parser": "@typescript-eslint/parser",
"parserOptions": {
"ecmaVersion": "latest",
"sourceType": "module",
"project": "./tsconfig.json"
},
"plugins": ["@typescript-eslint"],
"rules": {
// TypeScript specific rules
"@typescript-eslint/no-unused-vars": ["error", { "argsIgnorePattern": "^_" }],
"@typescript-eslint/no-explicit-any": "error",
"@typescript-eslint/no-unsafe-assignment": "error",
"@typescript-eslint/no-unsafe-call": "error",
"@typescript-eslint/no-unsafe-member-access": "error",
"@typescript-eslint/no-unsafe-return": "error",
"@typescript-eslint/prefer-nullish-coalescing": "error",
"@typescript-eslint/prefer-optional-chain": "error",
"@typescript-eslint/consistent-type-definitions": ["error", "interface"],
// General rules
"prefer-const": "error",
"no-var": "error",
"object-shorthand": "error",
"prefer-template": "error"
}
} {
"semi": true,
"singleQuote": true,
"tabWidth": 2,
"trailingComma": "es5",
"printWidth": 100,
"useTabs": false,
"bracketSpacing": true,
"arrowParens": "avoid"
} Set up an efficient development workflow with hot reloading, type checking, and testing.
# Install development dependencies
npm install --save-dev ts-node-dev nodemon concurrently
# For React/Vite projects
npm install --save-dev vite @vitejs/plugin-react {
"scripts": {
"dev": "concurrently \"npm:dev:server\" \"npm:type-check:watch\"",
"dev:server": "ts-node-dev --respawn --transpile-only src/server.ts",
"type-check:watch": "tsc --noEmit --watch",
"build": "npm run type-check && npm run build:compile",
"build:compile": "tsc",
"start": "node dist/server.js"
}
} {
"typescript.preferences.importModuleSpecifier": "relative",
"typescript.suggest.autoImports": true,
"typescript.updateImportsOnFileMove.enabled": "always",
"editor.formatOnSave": true,
"editor.codeActionsOnSave": {
"source.fixAll.eslint": true,
"source.organizeImports": true
},
"eslint.validate": [
"javascript",
"typescript"
],
"[typescript]": {
"editor.defaultFormatter": "esbenp.prettier-vscode"
},
"[typescriptreact]": {
"editor.defaultFormatter": "esbenp.prettier-vscode"
}
} {
"recommendations": [
"ms-vscode.vscode-typescript-next",
"esbenp.prettier-vscode",
"dbaeumer.vscode-eslint",
"bradlc.vscode-tailwindcss"
]
} # Install husky and lint-staged
npm install --save-dev husky lint-staged
# Initialize husky
npx husky install
# Add pre-commit hook
npx husky add .husky/pre-commit "npx lint-staged" {
"lint-staged": {
"*.{ts,tsx}": [
"eslint --fix",
"prettier --write",
"git add"
],
"*.{json,md}": [
"prettier --write",
"git add"
]
},
"husky": {
"hooks": {
"pre-commit": "lint-staged",
"pre-push": "npm run type-check"
}
}
} Organize your TypeScript project with a clear, scalable structure.
project-root/
├── src/
│ ├── components/ # React components (if applicable)
│ ├── services/ # API services and business logic
│ ├── utils/ # Utility functions
│ ├── types/ # Type definitions
│ │ ├── api.ts # API response types
│ │ ├── user.ts # User-related types
│ │ └── index.ts # Barrel exports
│ ├── hooks/ # Custom React hooks (if applicable)
│ ├── constants/ # Application constants
│ ├── config/ # Configuration files
│ └── index.ts # Entry point
├── tests/
│ ├── __mocks__/ # Jest mocks
│ ├── unit/ # Unit tests
│ └── integration/ # Integration tests
├── dist/ # Compiled output
├── .eslintrc.json
├── .prettierrc
├── tsconfig.json
├── jest.config.js
└── package.json // src/types/user.ts
export interface User {
id: string;
name: string;
email: string;
role: UserRole;
}
export type UserRole = 'admin' | 'user' | 'guest';
export interface CreateUserRequest {
name: string;
email: string;
role?: UserRole;
}
// src/types/api.ts
export interface ApiResponse<T> {
data: T;
status: 'success' | 'error';
message?: string;
}
export interface PaginatedResponse<T> extends ApiResponse<T[]> {
pagination: {
page: number;
limit: number;
total: number;
};
}
// src/types/index.ts - Barrel exports
export * from './user';
export * from './api';