TypeScript Project Setup for Beginners

Set up a complete TypeScript project from scratch. Create a tsconfig.json, organize source and output folders, add build scripts, and run your code with one command.

6 min read

Setting up a TypeScript project means creating a folder with three things: a package.json for dependencies and scripts, a tsconfig.json for compiler settings, and a src/ folder for your code. This setup works for any TypeScript project, from a small script to a large application.

Let's build it step by step. By the end, you will have a project that compiles and runs with a single command.

Step 1: Create the Project Folder

Every TypeScript project starts as an empty folder that you turn into an npm package. Create the folder, move into it, and initialize npm in one go:

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

The -y flag accepts every default answer instead of asking you questions one at a time, and the command creates a package.json with your project name and basic metadata.

Step 2: Install TypeScript

Install TypeScript as a development dependency. This makes it available inside the project without requiring a global install:

bashbash
npm install -D typescript

Your package.json file now lists TypeScript as a dependency, with the exact version pinned so every install matches across your whole team:

jsonjson
{
  "devDependencies": {
    "typescript": "^7.0.0"
  }
}

Installing locally means everyone on your team gets the same version when they run npm install. It also means your CI server does not need a global TypeScript install.

To run the locally installed compiler, use npx:

bashbash
npx tsc --version

npx runs executables from node_modules/.bin/. You will use it whenever you need the tsc command inside the project.

Step 3: Create tsconfig.json

Generate a tsconfig.json with all available options:

bashbash
npx tsc --init

The generated file has every option listed with comments. You only need to set a handful. Open tsconfig.json and edit these fields:

jsonjson
{
  "compilerOptions": {
    "target": "ES2022",
    "module": "NodeNext",
    "rootDir": "./src",
    "outDir": "./dist",
    "strict": true,
    "esModuleInterop": true
  },
  "include": ["src"]
}

This covers the essentials: which JavaScript version to emit, which module system to use, where your source and compiled files live, and strict type checking. Two more options are worth adding the same way for a smoother experience, listed in the table below along with everything else.

What each option does:

OptionPurpose
target: "ES2022"Emit modern JavaScript for recent Node.js versions
module: "NodeNext"Use Node.js native ES module system
rootDir: "./src"TypeScript source files live in src/
outDir: "./dist"Compiled JavaScript goes into dist/
strict: trueEnable all strict type checks
esModuleInterop: trueBetter compatibility with CommonJS modules
skipLibCheck: trueSkip type checking of library declaration files for faster builds
include: ["src"]Only compile files in the src/ folder

This is the configuration most new TypeScript projects start with. Adjust target and module if you are targeting browsers or an older Node.js version.

Step 4: Create the Source Folder

Create the src/ folder for your source files:

bashbash
mkdir src

Inside that new folder, create a file called src/index.ts and give it two small typed functions, one that builds a greeting and one that adds two numbers together:

typescripttypescript
function greet(name: string): string {
  return `Hello, ${name}! Welcome to TypeScript.`;
}
 
function add(a: number, b: number): number {
  return a + b;
}

Call both functions and print the results at the bottom of the same file, right after the two function declarations:

typescripttypescript
const message = greet("Alex");
const sum = add(5, 10);
 
console.log(message);
console.log(`5 + 10 = ${sum}`);

This file has typed functions and some runtime logic. It is small but shows the pattern you will use for every file: write the logic, add types to the function signatures.

Step 5: Add Build and Start Scripts

Open package.json and add two scripts to the "scripts" section:

jsonjson
{
  "scripts": {
    "build": "tsc",
    "start": "node dist/index.js",
    "dev": "tsc --watch"
  }
}
  • build compiles your TypeScript to JavaScript.
  • start runs the compiled output.
  • dev watches for changes and recompiles automatically.

Because TypeScript is installed locally, npm run build finds tsc in node_modules/.bin/ automatically. You do not need npx in npm scripts.

Step 6: Build and Run

Compile the whole project with the build script you just added, which runs tsc under the hood:

bashbash
npm run build

You should see no errors in the terminal, and a new dist/ folder appears containing the compiled output. Open dist/index.js to see the two functions with their types stripped:

javascriptjavascript
function greet(name) {
    return `Hello, ${name}! Welcome to TypeScript.`;
}
function add(a, b) {
    return a + b;
}

The output keeps const and the template literal exactly as written, because the tsconfig.json from Step 3 sets target to ES2022, which supports both natively. Only the type annotations are gone, and the two function calls at the bottom stay unchanged too:

javascriptjavascript
const message = greet("Alex");
const sum = add(5, 10);
console.log(message);
console.log(`5 + 10 = ${sum}`);

Now run the freshly compiled JavaScript with the start script, which just calls node directly on the output file for you automatically:

bashbash
npm start

Running that script starts Node.js on the compiled dist/index.js file, and the two console.log calls inside it print straight to the terminal:

texttext
Hello, Alex! Welcome to TypeScript.
5 + 10 = 15

You now have a complete TypeScript project. Write code in src/, run npm run build to compile, and npm start to execute.

Step 7: Add a Second File

Real projects almost always span multiple files. Create a second file called src/utils.ts with two small exported helper functions:

typescripttypescript
export function formatCurrency(amount: number): string {
  return `$${amount.toFixed(2)}`;
}
 
export function capitalize(text: string): string {
  return text.charAt(0).toUpperCase() + text.slice(1);
}

Update the entry file at src/index.ts to import both functions from the new file and use them in place of the earlier greeting example:

typescripttypescript
import { formatCurrency, capitalize } from "./utils.js";
 
const price = formatCurrency(29.99);
const title = capitalize("typescript project");
 
console.log(title);
console.log(`Price: ${price}`);

Notice the import path uses "./utils.js", not "./utils.ts". TypeScript expects the import to reference the compiled JavaScript file extension. When you write import from "./utils.js", the compiler resolves it to ./utils.ts during type checking and emits the same "./utils.js" path in the output.

Rebuild the project and run it again the same way as before, so both files compile together:

bashbash
npm run build && npm start

The two functions from utils.ts now produce the formatted output, and index.ts prints both values straight to the terminal below:

texttext
Typescript project
Price: $29.99

Project Structure Overview

After adding a second source file and rebuilding, here is the complete folder layout your project now has, with the source and compiled output kept in separate places:

texttext
my-typescript-project/
  node_modules/        # Installed dependencies
  src/                 # TypeScript source files
    index.ts           # Entry point
    utils.ts           # Shared utilities
  dist/                # Compiled JavaScript (generated by tsc)
    index.js
    utils.js
  package.json         # Dependencies and scripts
  tsconfig.json        # TypeScript configuration

The dist/ folder is generated output, not something you write by hand, so it does not belong in version control. Add both generated folders to your .gitignore file:

bashbash
echo "dist/" >> .gitignore
echo "node_modules/" >> .gitignore

Running During Development

Running the build script by hand after every single change gets tedious fast. During development, use watch mode instead, so the compiler recompiles automatically every time you save a file:

bashbash
npm run dev

The compiler starts, checks the project once, and then keeps running in the terminal, printing a status line instead of exiting:

texttext
[10:30:00 AM] Starting compilation in watch mode...
[10:30:00 AM] Found 0 errors. Watching for file changes.

Make a change to src/index.ts, save, and the terminal updates immediately with any errors. Keep this running in a terminal while you work.

To run the code after each change, you have two options. For a quick check, open a second terminal and run npm start. For automatic re-running, install tsx and use its watch mode:

bashbash
npm install -D tsx

Add a new dev-and-run script to package.json that pairs tsx --watch with your entry file, so a single command handles both compiling and running together:

jsonjson
{
  "scripts": {
    "build": "tsc",
    "start": "node dist/index.js",
    "dev": "tsc --watch",
    "dev:run": "tsx --watch src/index.ts"
  }
}

Now npm run dev:run compiles and runs your TypeScript in one step, restarting on every save. This is the fastest feedback loop for development.

Next Steps

Your project is ready. From here, you can explore TypeScript basics to learn the type system, or dive into compiler and strict mode to understand every option in your tsconfig.

Rune AI

Rune AI

Key Insights

  • Initialize with npm init -y and install TypeScript with npm install -D typescript.
  • Generate tsconfig.json with tsc --init, then set target, module, outDir, rootDir, and strict.
  • Put source files in src/ and compiled output in dist/.
  • Add build and start scripts to package.json for one-command build and run.
  • Use tsc --watch during development for instant feedback on type errors.
RunePowered by Rune AI

Frequently Asked Questions

Should I install TypeScript globally or locally?

Install it locally in your project with `npm install -D typescript`. This locks the version for your team and CI. Global installs are fine for quick scripts but not for shared projects.

What folder structure should I use?

The most common pattern is `src/` for TypeScript source files and `dist/` for compiled JavaScript output. Keep your tsconfig.json and package.json in the project root.

Do I need a bundler like Webpack or Vite with TypeScript?

Not for Node.js projects. tsc compiles directly to JavaScript that Node.js can run. For browser projects, a bundler like Vite is helpful for handling CSS, images, and hot reload, but it is not required for TypeScript itself.

Conclusion

A TypeScript project is a folder with a package.json, a tsconfig.json, and a src/ directory full of .ts files. Run tsc to compile everything to dist/, then node dist/index.js to run it. Add npm scripts for build and start, and you have a professional setup that takes five minutes to create and scales to any project size.