Skip to main content

Getting Started with TypeScript (TypeScript init)

You want to start using TypeScript, but you're staring at an empty project folder wondering where to begin. Should you just create a tsconfig.json by hand? Copy one from another project? The answer is simpler than you think: tsc --init does the heavy lifting for you.

This guide will walk you through initializing TypeScript projects using tsc --init, explain what actually happens when you run it, and show you how to customize the generated configuration for real-world projects. Whether you're starting fresh or adding TypeScript to an existing JavaScript codebase, you'll learn the practical steps and configuration choices that matter.

Quick Start: Complete Setup in One Command

If you're starting completely from scratch and want the fastest path to a working TypeScript project, run this:

npm init -y && npm install -D typescript && npx tsc --init

This does three things in sequence:

  • Creates a package.json file for your project
  • Installs TypeScript as a development dependency
  • Generates a tsconfig.json configuration file

You'll now have TypeScript ready to use. Skip to the Running and Compiling section to start building.

Step-by-Step Setup

If you prefer to understand each step (or you're adding TypeScript to an existing project), here's the breakdown.

1. Install TypeScript

First, you need TypeScript installed in your project. Install it as a development dependency:

npm install typescript --save-dev

Why --save-dev? Because TypeScript is a build tool. Your production code runs JavaScript, not TypeScript, so you don't need it in production dependencies.

2. Initialize TypeScript Configuration

Now run the initialization command:

npx tsc --init

This creates a tsconfig.json file in your project root. The file tells the TypeScript compiler how to process your code—what JavaScript version to target, where to put compiled files, how strict to be with type checking, and dozens of other options.

3. Start Writing TypeScript

Create a .ts file and start coding. For example, create src/index.ts:

// src/index.ts
interface UserProfile {
id: number;
email: string;
preferences?: Record<string, boolean>;
}

function validateUser(user: UserProfile): boolean {
return user.id > 0 && user.email.includes('@');
}

const currentUser: UserProfile = {
id: 1,
email: 'developer@example.com'
};

console.log(validateUser(currentUser)); // true

You can now take advantage of typescript interface definitions and type annotations to catch bugs before they reach production.

What tsc --init Actually Creates

When you run tsc --init, TypeScript generates a tsconfig.json file with sensible defaults. The actual file contains dozens of commented-out options (so you can see what's available), but here's what it enables by default:

{
"compilerOptions": {
"target": "es2016",
"module": "commonjs",
"strict": true,
"esModuleInterop": true,
"skipLibCheck": true,
"forceConsistentCasingInFileNames": true
}
}

These defaults give you a solid foundation, but you'll likely want to customize them based on your project needs.

Essential Compiler Options Explained

The tsconfig.json file is where you control TypeScript's behavior. Here are the options you'll adjust most often:

strict

{
"compilerOptions": {
"strict": true
}
}

This is the single most important option. It enables all strict type-checking options at once, catching common bugs like accessing properties that might be undefined or using any implicitly. Always leave this enabled unless you're gradually migrating a large JavaScript codebase.

target

{
"compilerOptions": {
"target": "es2022"
}
}

Controls what JavaScript version TypeScript compiles to. If you're building for modern browsers or Node.js 16+, use es2022 or es2021. For broader compatibility, stick with es2016. You can adjust this based on your typescript versions and runtime requirements.

module

{
"compilerOptions": {
"module": "NodeNext" // For Node.js projects
}
}

Sets the module system. Use NodeNext for Node.js projects to get proper ESM support. For frontend projects using a bundler, your build tool (like Vite or webpack) usually handles this, so you can use ESNext.

outDir and rootDir

{
"compilerOptions": {
"rootDir": "./src",
"outDir": "./dist"
}
}

These keep your project organized. rootDir is where your .ts source files live, and outDir is where compiled .js files go. This separation makes it easy to exclude build output from version control and deploy only what's needed.

skipLibCheck

{
"compilerOptions": {
"skipLibCheck": true
}
}

Skips type-checking of declaration files (.d.ts). This speeds up compilation significantly, especially in large projects with many dependencies. There's rarely a reason to turn this off.

Additional Must-Have Options

Here are a few more options you should add to the default configuration:

{
"compilerOptions": {
"isolatedModules": true, // Ensures each file can be safely transpiled independently
"moduleDetection": "force", // Prevents "cannot redeclare block-scoped variable" errors
"resolveJsonModule": true, // Lets you import JSON files with type safety
"allowJs": true // Useful when migrating from JavaScript
}
}

Running and Compiling TypeScript

Once you've set up your tsconfig.json, you need to actually compile your TypeScript code to JavaScript.

Basic Compilation

Compile all TypeScript files in your project:

npx tsc

This reads your tsconfig.json, finds all .ts files (based on include/exclude patterns), and outputs JavaScript to your outDir.

Watch Mode

For active development, use watch mode to automatically recompile when files change:

npx tsc -w

Now every time you save a .ts file, TypeScript recompiles it instantly. This is what you'll run most often during development.

Compiling a Single File

If you need to compile just one file (ignoring tsconfig.json):

npx tsc src/utils.ts

This outputs src/utils.js in the same directory. However, for most projects, you'll want to rely on your tsconfig.json and compile everything together with npx tsc.

Adding Build Scripts

Add these to your package.json for convenience:

{
"scripts": {
"build": "tsc",
"dev": "tsc -w"
}
}

Now you can run npm run build or npm run dev instead of typing npx tsc repeatedly.

For Node.js projects, you might also want to integrate this with npm tooling like ts-node for running TypeScript directly during development.

Here's a production-ready tsconfig.json that works well for most Node.js projects:

{
"compilerOptions": {
// Language and environment
"target": "es2022",
"module": "NodeNext",
"lib": ["es2022"],

// Module resolution
"moduleResolution": "NodeNext",
"resolveJsonModule": true,
"allowJs": true,

// Emit
"outDir": "./dist",
"rootDir": "./src",
"sourceMap": true,

// Type checking
"strict": true,
"noUncheckedIndexedAccess": true,

// Interop and performance
"esModuleInterop": true,
"skipLibCheck": true,
"forceConsistentCasingInFileNames": true,
"isolatedModules": true,
"moduleDetection": "force"
},
"include": ["src/**/*"],
"exclude": ["node_modules", "dist"]
}

For frontend projects using React, you'll need different settings. Check out TypeScript with React for framework-specific configuration that provides end-to-end type safety.

Problems You Might Encounter

"Cannot find module" errors after running tsc

You ran tsc --init and started writing TypeScript, but now you're getting module resolution errors. This usually means your moduleResolution doesn't match your module setting.

Solution: If you're using "module": "NodeNext", you must also use "moduleResolution": "NodeNext". They work as a pair:

{
"compilerOptions": {
"module": "NodeNext",
"moduleResolution": "NodeNext"
}
}

Compiled files aren't appearing in the output directory

You set outDir to ./dist, but after running tsc, no files appear there.

Solution: Make sure you're running npx tsc without specifying a filename. If you run npx tsc index.ts, it ignores your tsconfig.json entirely and outputs to the same directory as the source file. Just run npx tsc by itself.

"Cannot redeclare block-scoped variable" errors

You're seeing errors about variables being declared multiple times, even though they're in different files.

Solution: Add "moduleDetection": "force" to your compiler options. This tells TypeScript to treat every file as a module, preventing global scope pollution:

{
"compilerOptions": {
"moduleDetection": "force"
}
}

Migrating an existing JavaScript project to TypeScript

You want to add TypeScript to a large JavaScript codebase without rewriting everything at once.

Solution: Start with these compiler options:

{
"compilerOptions": {
"allowJs": true, // Let .js and .ts files coexist
"checkJs": false, // Don't type-check .js files yet
"strict": false // Start lenient, tighten later
}
}

Then gradually:

  1. Rename one file at a time from .js to .ts
  2. Fix the type errors in that file
  3. Use interface and type to define your data structures
  4. Once most files are converted, enable strict mode

Enabling experimental features like decorators

If you're using frameworks that require decorators (like TypeORM or NestJS), you need to enable them explicitly.

Solution: Add these options for TypeScript decorators:

{
"compilerOptions": {
"experimentalDecorators": true,
"emitDecoratorMetadata": true
}
}

Key Takeaways

Getting started with TypeScript boils down to a few essential steps:

  1. Install TypeScript locally with npm install typescript --save-dev
  2. Run npx tsc --init to generate your tsconfig.json
  3. Enable strict mode and keep it enabled
  4. Set outDir and rootDir to keep source and build files separate
  5. Use watch mode (npx tsc -w) during development for instant feedback

The tsconfig.json you create with tsc --init isn't set in stone. As your project evolves, you'll adjust compiler options, add stricter type checks, and fine-tune settings to match your needs. That's normal. The configuration grows with your understanding.

Whether you're building React applications, Node.js servers, or full-stack applications with technologies like Convex (which has excellent TypeScript support for building modern apps), you now have the foundation to work confidently with TypeScript from day one.