guideFeatured

Complete TypeScript Project Setup Guide

A step-by-step guide to setting up a modern TypeScript project with best practices for developer experience.

Hunchbite Team
January 20, 2025
15 min read
typescriptsetupdxtoolingconfiguration

Complete TypeScript Project Setup Guide

Setting up a TypeScript project correctly from the start can save you hours of debugging and configuration headaches later. This guide walks you through creating a modern TypeScript project with optimal developer experience.

Prerequisites

  • Node.js 18+ installed
  • A code editor (VS Code recommended)
  • Basic familiarity with TypeScript

Step 1: Project Initialization

Create the project structure

mkdir my-typescript-project
cd my-typescript-project
npm init -y

Install TypeScript and essential dependencies

npm install typescript @types/node --save-dev
npm install ts-node nodemon --save-dev

Step 2: TypeScript Configuration

Create tsconfig.json

{
  "compilerOptions": {
    "target": "ES2022",
    "module": "ESNext",
    "moduleResolution": "bundler",
    "allowImportingTsExtensions": true,
    "noEmit": true,
    "strict": true,
    "noUnusedLocals": true,
    "noUnusedParameters": true,
    "noFallthroughCasesInSwitch": true,
    "noUncheckedIndexedAccess": true,
    "exactOptionalPropertyTypes": true,
    "skipLibCheck": true,
    "forceConsistentCasingInFileNames": true,
    "allowSyntheticDefaultImports": true,
    "esModuleInterop": true,
    "allowJs": true,
    "incremental": true,
    "tsBuildInfoFile": ".tsbuildinfo",
    "baseUrl": ".",
    "paths": {
      "@/*": ["./src/*"]
    }
  },
  "include": ["src/**/*"],
  "exclude": ["node_modules", "dist", "**/*.test.ts", "**/*.spec.ts"]
}

Key configuration explanations

  • strict: true: Enables all strict type checking options
  • noUncheckedIndexedAccess: Adds undefined to index signatures
  • exactOptionalPropertyTypes: More precise optional property handling
  • incremental: true: Enables faster rebuilds
  • paths: Enables clean imports with @/ prefix

Step 3: Development Environment Setup

VS Code Configuration

Create .vscode/settings.json:

{
  "typescript.preferences.includePackageJsonAutoImports": "off",
  "typescript.suggest.autoImports": true,
  "typescript.updateImportsOnFileMove.enabled": "always",
  "editor.codeActionsOnSave": {
    "source.fixAll.eslint": "explicit",
    "source.organizeImports": "explicit"
  },
  "editor.formatOnSave": true,
  "editor.defaultFormatter": "esbenp.prettier-vscode"
}

Install ESLint and Prettier

npm install eslint @typescript-eslint/parser @typescript-eslint/eslint-plugin --save-dev
npm install prettier eslint-config-prettier eslint-plugin-prettier --save-dev

ESLint Configuration

Create .eslintrc.js:

module.exports = {
  parser: '@typescript-eslint/parser',
  parserOptions: {
    ecmaVersion: 2022,
    sourceType: 'module',
  },
  plugins: ['@typescript-eslint'],
  extends: [
    'eslint:recommended',
    '@typescript-eslint/recommended',
    'prettier',
  ],
  rules: {
    '@typescript-eslint/no-unused-vars': 'error',
    '@typescript-eslint/no-explicit-any': 'warn',
    '@typescript-eslint/prefer-const': 'error',
    '@typescript-eslint/no-var-requires': 'error',
  },
};

Prettier Configuration

Create .prettierrc:

{
  "semi": true,
  "trailingComma": "es5",
  "singleQuote": true,
  "printWidth": 80,
  "tabWidth": 2,
  "useTabs": false
}

Step 4: Build and Development Tools

Package.json Scripts

Update your package.json:

{
  "scripts": {
    "dev": "tsx watch src/index.ts",
    "build": "tsc",
    "start": "node dist/index.js",
    "lint": "eslint src --ext .ts",
    "lint:fix": "eslint src --ext .ts --fix",
    "format": "prettier --write src/**/*.ts",
    "type-check": "tsc --noEmit"
  }
}

Install tsx for development

npm install tsx --save-dev

Step 5: Project Structure

Create this folder structure:

src/
├── index.ts
├── types/
│   └── index.ts
├── utils/
│   └── index.ts
├── services/
│   └── index.ts
└── config/
    └── index.ts

Example index.ts

import { config } from './config';
import { logger } from './utils/logger';

async function main() {
  try {
    logger.info('Starting application...');
    // Your application logic here
    logger.info('Application started successfully');
  } catch (error) {
    logger.error('Failed to start application:', error);
    process.exit(1);
  }
}

main();

Step 6: Environment Configuration

Install dotenv

npm install dotenv

Create environment files

.env.example:

NODE_ENV=development
PORT=3000
DATABASE_URL=postgresql://localhost:5432/myapp
API_KEY=your-api-key-here

.env:

NODE_ENV=development
PORT=3000
DATABASE_URL=postgresql://localhost:5432/myapp
API_KEY=your-actual-api-key

Environment configuration

Create src/config/index.ts:

import dotenv from 'dotenv';

dotenv.config();

export const config = {
  nodeEnv: process.env.NODE_ENV || 'development',
  port: parseInt(process.env.PORT || '3000', 10),
  databaseUrl: process.env.DATABASE_URL,
  apiKey: process.env.API_KEY,
} as const;

// Type-safe config access
export type Config = typeof config;

Step 7: Testing Setup

Install testing dependencies

npm install vitest @vitest/ui --save-dev
npm install @types/jest --save-dev

Vitest Configuration

Create vitest.config.ts:

import { defineConfig } from 'vitest/config';
import { resolve } from 'path';

export default defineConfig({
  test: {
    globals: true,
    environment: 'node',
  },
  resolve: {
    alias: {
      '@': resolve(__dirname, './src'),
    },
  },
});

Add test script

Update package.json:

{
  "scripts": {
    "test": "vitest",
    "test:ui": "vitest --ui",
    "test:coverage": "vitest --coverage"
  }
}

Step 8: Git Configuration

.gitignore

Create .gitignore:

# Dependencies
node_modules/

# Build outputs
dist/
build/

# Environment files
.env
.env.local
.env.*.local

# IDE files
.vscode/
.idea/

# OS files
.DS_Store
Thumbs.db

# Logs
*.log
npm-debug.log*

# TypeScript build info
.tsbuildinfo

# Test coverage
coverage/

# Temporary files
*.tmp
*.temp

Git hooks (optional)

Install husky for git hooks:

npm install husky lint-staged --save-dev
npx husky install
npx husky add .husky/pre-commit "npx lint-staged"

Create .lintstagedrc.js:

module.exports = {
  '*.ts': ['eslint --fix', 'prettier --write'],
  '*.js': ['eslint --fix', 'prettier --write'],
  '*.json': ['prettier --write'],
};

Step 9: Documentation

README.md

Create a comprehensive README:

# My TypeScript Project

A modern TypeScript project with optimal developer experience.

## Getting Started

1. Install dependencies:
   ```bash
   npm install
  1. Set up environment variables:

    cp .env.example .env
    # Edit .env with your values
    
  2. Start development server:

    npm run dev
    

Available Scripts

  • npm run dev - Start development server
  • npm run build - Build for production
  • npm run start - Start production server
  • npm run lint - Run ESLint
  • npm run lint:fix - Fix ESLint issues
  • npm run format - Format code with Prettier
  • npm run test - Run tests
  • npm run type-check - Type check without emitting

Project Structure

  • src/ - Source code
  • src/types/ - TypeScript type definitions
  • src/utils/ - Utility functions
  • src/services/ - Business logic services
  • src/config/ - Configuration files

Contributing

  1. Fork the repository
  2. Create a feature branch
  3. Make your changes
  4. Run tests and linting
  5. Submit a pull request

## Step 10: Performance Optimization

### Bundle Analysis

Install bundle analyzer:

```bash
npm install --save-dev webpack-bundle-analyzer

Add performance monitoring

npm install --save-dev speed-measure-webpack-plugin

Best Practices Summary

  1. Use strict TypeScript configuration - Catches more errors at compile time
  2. Set up proper linting and formatting - Ensures code consistency
  3. Configure path aliases - Makes imports cleaner and more maintainable
  4. Use environment variables - Keeps configuration separate from code
  5. Set up testing early - Makes it easier to maintain code quality
  6. Document everything - Helps with onboarding and maintenance

Common Issues and Solutions

Issue: Slow TypeScript compilation

Solution: Enable incremental compilation and use project references for large codebases.

Issue: Import paths getting messy

Solution: Use path aliases and organize code into logical modules.

Issue: Environment variables not typed

Solution: Create a typed config object and validate environment variables.

Issue: Inconsistent code formatting

Solution: Use Prettier with editor integration and pre-commit hooks.

This setup provides a solid foundation for any TypeScript project. You can customize it based on your specific needs, but this configuration will give you excellent developer experience from day one.


This guide is part of our Developer Experience Engineering series. Follow us for more TypeScript and DX optimization tips.