BLOG POSTS
TypeScript New Project – Getting Started Guide

TypeScript New Project – Getting Started Guide

TypeScript has evolved from being just “JavaScript with types” into a powerhouse for building scalable, maintainable applications. Setting up a new TypeScript project might seem straightforward, but getting the configuration right from the start can save you countless hours of debugging and refactoring later. This guide walks you through creating a solid TypeScript foundation, covering everything from basic setup to advanced configurations, common gotchas you’ll definitely encounter, and best practices that experienced developers swear by.

How TypeScript Projects Work

TypeScript operates as a compile-time layer over JavaScript, transforming your strongly-typed code into browser-compatible JavaScript. The core of any TypeScript project revolves around the tsconfig.json file, which acts as the blueprint for how your code gets compiled, what rules are enforced, and where outputs end up.

The compilation process involves several key components:

  • The TypeScript compiler (tsc) reads your source files and configuration
  • Type checking occurs before any JavaScript is generated
  • Source maps can be generated for debugging purposes
  • Output files are placed according to your specified directory structure

Modern TypeScript projects often integrate with bundlers like Webpack, Vite, or esbuild, but understanding the core TypeScript compilation process helps when things go sideways.

Step-by-Step Project Setup

Let’s build a TypeScript project from scratch. I’ll show you the manual approach first because understanding each piece makes troubleshooting much easier later.

Initialize Your Project

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

Install TypeScript Dependencies

# Install TypeScript compiler globally (optional but handy)
npm install -g typescript

# Install TypeScript as dev dependency for the project
npm install --save-dev typescript @types/node

# For development convenience
npm install --save-dev ts-node nodemon

Create TypeScript Configuration

Generate a basic tsconfig.json:

npx tsc --init

This creates a comprehensive config file, but it’s overly complex for most projects. Here’s a cleaner starting configuration:

{
  "compilerOptions": {
    "target": "ES2020",
    "module": "commonjs",
    "lib": ["ES2020"],
    "outDir": "./dist",
    "rootDir": "./src",
    "strict": true,
    "esModuleInterop": true,
    "skipLibCheck": true,
    "forceConsistentCasingInFileNames": true,
    "resolveJsonModules": true,
    "declaration": true,
    "declarationMap": true,
    "sourceMap": true
  },
  "include": ["src/**/*"],
  "exclude": ["node_modules", "dist"]
}

Set Up Project Structure

mkdir src
mkdir dist
touch src/index.ts

Configure Package.json Scripts

{
  "scripts": {
    "build": "tsc",
    "start": "node dist/index.js",
    "dev": "nodemon --exec ts-node src/index.ts",
    "clean": "rm -rf dist/*"
  }
}

Create Your First TypeScript File

Add this to src/index.ts:

interface User {
  id: number;
  name: string;
  email: string;
}

class UserService {
  private users: User[] = [];

  addUser(user: Omit<User, 'id'>): User {
    const newUser: User = {
      id: this.users.length + 1,
      ...user
    };
    this.users.push(newUser);
    return newUser;
  }

  getUser(id: number): User | undefined {
    return this.users.find(user => user.id === id);
  }

  getAllUsers(): readonly User[] {
    return Object.freeze([...this.users]);
  }
}

const userService = new UserService();
const user = userService.addUser({
  name: "John Doe",
  email: "john@example.com"
});

console.log("Created user:", user);
console.log("All users:", userService.getAllUsers());

Real-World Project Examples

Express API Server Setup

For web APIs, you’ll want additional dependencies:

npm install express
npm install --save-dev @types/express

Enhanced tsconfig.json for server projects:

{
  "compilerOptions": {
    "target": "ES2020",
    "module": "commonjs",
    "lib": ["ES2020"],
    "outDir": "./dist",
    "rootDir": "./src",
    "strict": true,
    "esModuleInterop": true,
    "skipLibCheck": true,
    "forceConsistentCasingInFileNames": true,
    "experimentalDecorators": true,
    "emitDecoratorMetadata": true,
    "moduleResolution": "node",
    "allowSyntheticDefaultImports": true
  },
  "include": ["src/**/*"],
  "exclude": ["node_modules", "dist", "**/*.test.ts"]
}

Frontend Project with Modern Bundling

For frontend projects, integrate with Vite:

npm install --save-dev vite @vitejs/plugin-typescript

Create vite.config.ts:

import { defineConfig } from 'vite';
import typescript from '@vitejs/plugin-typescript';

export default defineConfig({
  plugins: [typescript()],
  build: {
    outDir: 'dist',
    sourcemap: true
  }
});

TypeScript vs JavaScript Alternatives

Feature TypeScript JavaScript + JSDoc Flow Pure JavaScript
Type Safety Compile-time IDE hints only Compile-time Runtime errors
Learning Curve Moderate Low Steep None
Ecosystem Excellent Good Limited Excellent
Build Step Required Optional Required None
Performance Same as JS Same as JS Same as JS Baseline

Best Practices and Common Pitfalls

Configuration Best Practices

  • Always enable strict mode – it catches more bugs upfront
  • Use skipLibCheck: true to avoid type issues in node_modules
  • Set forceConsistentCasingInFileNames: true for cross-platform compatibility
  • Enable sourceMap: true for better debugging experience
  • Use resolveJsonModules: true if you import JSON files

Common Pitfalls and Solutions

Pitfall: Module resolution errors with third-party packages

// Fix: Install type definitions
npm install --save-dev @types/package-name

// Or create custom declarations
declare module 'untyped-package' {
  export function someFunction(): string;
}

Pitfall: Import path issues between development and production

// Bad: Relative paths everywhere
import { helper } from '../../../utils/helper';

// Good: Use path mapping in tsconfig.json
{
  "compilerOptions": {
    "baseUrl": "./src",
    "paths": {
      "@utils/*": ["utils/*"],
      "@components/*": ["components/*"]
    }
  }
}

Pitfall: TypeScript config not being picked up

# Verify TypeScript can find your config
npx tsc --showConfig

# Check which files TypeScript will compile
npx tsc --listFiles

Performance Optimization

For large projects, compilation speed matters:

{
  "compilerOptions": {
    "incremental": true,
    "tsBuildInfoFile": ".tsbuildinfo"
  },
  "exclude": [
    "node_modules",
    "**/*.test.ts",
    "**/*.spec.ts"
  ]
}

Advanced Configuration Patterns

Monorepo Setup

For multi-package projects, use project references:

// Root tsconfig.json
{
  "files": [],
  "references": [
    { "path": "./packages/core" },
    { "path": "./packages/web" },
    { "path": "./packages/api" }
  ]
}

Environment-Specific Configurations

// tsconfig.production.json
{
  "extends": "./tsconfig.json",
  "compilerOptions": {
    "sourceMap": false,
    "removeComments": true
  },
  "exclude": [
    "src/**/*.test.ts",
    "src/**/*.spec.ts"
  ]
}

Custom Build Scripts

// package.json
{
  "scripts": {
    "build:dev": "tsc --watch",
    "build:prod": "tsc -p tsconfig.production.json",
    "type-check": "tsc --noEmit",
    "build:clean": "npm run clean && npm run build"
  }
}

Integration with Development Tools

ESLint Configuration

npm install --save-dev @typescript-eslint/parser @typescript-eslint/eslint-plugin
// .eslintrc.js
module.exports = {
  parser: '@typescript-eslint/parser',
  plugins: ['@typescript-eslint'],
  extends: [
    'eslint:recommended',
    '@typescript-eslint/recommended'
  ],
  parserOptions: {
    project: './tsconfig.json'
  }
};

Prettier Integration

// .prettierrc
{
  "semi": true,
  "trailingComma": "es5",
  "singleQuote": true,
  "printWidth": 80,
  "tabWidth": 2
}

The key to a successful TypeScript project is getting the foundation right from day one. Start with strict type checking enabled, use consistent tooling across your team, and don’t be afraid to adjust your tsconfig.json as your project grows. The initial setup investment pays dividends when your codebase scales and you need to refactor or debug complex issues.

For comprehensive documentation on all TypeScript compiler options, check the official TypeScript documentation. The TypeScript team also maintains excellent wiki resources covering advanced scenarios and best practices.



This article incorporates information and material from various online sources. We acknowledge and appreciate the work of all original authors, publishers, and websites. While every effort has been made to appropriately credit the source material, any unintentional oversight or omission does not constitute a copyright infringement. All trademarks, logos, and images mentioned are the property of their respective owners. If you believe that any content used in this article infringes upon your copyright, please contact us immediately for review and prompt action.

This article is intended for informational and educational purposes only and does not infringe on the rights of the copyright owners. If any copyrighted material has been used without proper credit or in violation of copyright laws, it is unintentional and we will rectify it promptly upon notification. Please note that the republishing, redistribution, or reproduction of part or all of the contents in any form is prohibited without express written permission from the author and website owner. For permissions or further inquiries, please contact us.

Leave a reply

Your email address will not be published. Required fields are marked