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.
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:
mkdir my-typescript-project
cd my-typescript-project
npm init -yThe -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:
npm install -D typescriptYour package.json file now lists TypeScript as a dependency, with the exact version pinned so every install matches across your whole team:
{
"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:
npx tsc --versionnpx 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:
npx tsc --initThe generated file has every option listed with comments. You only need to set a handful. Open tsconfig.json and edit these fields:
{
"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:
| Option | Purpose |
|---|---|
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: true | Enable all strict type checks |
esModuleInterop: true | Better compatibility with CommonJS modules |
skipLibCheck: true | Skip 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:
mkdir srcInside 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:
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:
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:
{
"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:
npm run buildYou 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:
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:
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:
npm startRunning 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:
Hello, Alex! Welcome to TypeScript.
5 + 10 = 15You 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:
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:
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:
npm run build && npm startThe two functions from utils.ts now produce the formatted output, and index.ts prints both values straight to the terminal below:
Typescript project
Price: $29.99Project 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:
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 configurationThe 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:
echo "dist/" >> .gitignore
echo "node_modules/" >> .gitignoreRunning 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:
npm run devThe compiler starts, checks the project once, and then keeps running in the terminal, printing a status line instead of exiting:
[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:
npm install -D tsxAdd 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:
{
"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
Key Insights
- Initialize with
npm init -yand install TypeScript withnpm install -D typescript. - Generate tsconfig.json with
tsc --init, then settarget,module,outDir,rootDir, andstrict. - Put source files in
src/and compiled output indist/. - Add
buildandstartscripts to package.json for one-command build and run. - Use
tsc --watchduring development for instant feedback on type errors.
Frequently Asked Questions
Should I install TypeScript globally or locally?
What folder structure should I use?
Do I need a bundler like Webpack or Vite with TypeScript?
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.
More in this topic
TypeScript Compiler Explained
The TypeScript compiler (tsc) turns .ts files into .js files while checking types. Learn what it does, how to use it, and how it fits your workflow.
Set Up ESLint for TypeScript
Install and configure ESLint with typescript-eslint to catch bugs and enforce consistent code style in your TypeScript project.
Pick Utility Type in TypeScript
Pick creates a new type by selecting only the properties you name from an existing type. Use it to build focused types for specific views, API responses, or function parameters.