Skip to content

TypeScript Introduction and Setup

TypeScript is a programming language that is built on top of JavaScript, but it adds something extra: static types. This means TypeScript lets you catch mistakes early, before your code even runs, which makes working with JavaScript faster and more reliable.

TypeScript is what we call a superset of JavaScript. This simply means that any valid JavaScript code is also valid TypeScript code. On top of that, TypeScript adds extra features like static typing (checking the type of your data) and checks that happen while your code is being compiled.

You write your code in .ts files, and then the TypeScript compiler (called tsc) turns them into regular .js files that can actually run.

graph TD A[Write .ts file] --> B[Type Checking] B --> C[Transpile to .js] C --> D[Run in Browser or Node.js]
  • Type mistakes are caught before your code even runs.
  • When the code actually runs, it runs as plain JavaScript, not as TypeScript. TypeScript only exists while you are writing and compiling the code.
Terminal window
npm install -g typescript
tsc --version

If your project already has TypeScript listed in devDependencies, it is better to run it locally like this instead:

Terminal window
npx tsc --version
Terminal window
tsc --init

This command creates a file called tsconfig.json. This file controls how TypeScript behaves in your project.

{
"compilerOptions": {
"strict": true,
"target": "ES2020",
"module": "ESNext",
"outDir": "./dist",
"rootDir": "./src",
"moduleResolution": "Bundler",
"skipLibCheck": true
},
"include": ["src"]
}

strict

This turns on strong type checking. It is the most important setting for any real, serious project.

target

This decides which version of JavaScript gets created as output.

module

This controls the type of module syntax (like import/export) used in the final output.

outDir

This is the folder where your compiled JavaScript files will be placed.

When strict is set to true, TypeScript automatically turns on several checks, such as:

  • noImplicitAny
  • strictNullChecks
  • strictFunctionTypes
  • strictBindCallApply

These checks help stop a lot of bugs from happening, especially in big projects.

The tsconfig.json file is a configuration file that tells TypeScript how to compile your code. You can think of it as a rulebook that the TypeScript compiler follows.

  • Which JavaScript version your code gets converted into (ES2020, ES2015, and so on)
  • Which module system is used (CommonJS, ESM, and so on)
  • Where to find your source files
  • Where to put the compiled JavaScript files
  • How strict the type checking should be
  • Which files should be included or left out

TypeScript only works properly when tsconfig.json exists in the root folder of your project. Without this file, the compiler has no way of knowing your preferences.

A complete tsconfig.json file usually has three main parts:

{
"compilerOptions": {
// Controls how TypeScript compiles code
},
"include": ["src"], // Which files to compile
"exclude": ["node_modules", "dist"] // Which folders to skip
}

These are the settings that control how the compiling actually happens:

{
"compilerOptions": {
"strict": true,
"target": "ES2020",
"module": "ESNext",
"outDir": "./dist",
"rootDir": "./src",
"moduleResolution": "node",
"declaration": true,
"sourceMap": true,
"noImplicitAny": true,
"noUnusedLocals": true,
"noUnusedParameters": true,
"noImplicitReturns": true,
"allowJs": true,
"forceConsistentCasingInFileNames": true
}
}

This tells TypeScript exactly which files it should compile:

{
"include": [
"src/**/*", // All files in src folder
"src/**/*.ts", // Only .ts files
"tests/**/*.test.ts" // Include test files
]
}

This tells TypeScript which files or folders it should ignore completely:

{
"exclude": [
"node_modules",
"dist",
"build",
"**/*.spec.ts",
"**/*.test.ts"
]
}

strict

This is the master switch for all strict type checking. When set to true, it turns on: noImplicitAny, strictNullChecks, strictFunctionTypes, strictBindCallApply, strictPropertyInitialization, and noImplicitThis.

target

This decides which version of JavaScript is created as output. Common values are “ES2020”, “ES2015”, and “ES2022”. A higher target usually means smaller output, but it may not work in older browsers.

module

This controls the module system used in the output. “ESNext” means modern import/export syntax, while “CommonJS” means the older require/module.exports style.

moduleResolution

This decides how import paths are figured out. “node” means npm-style resolution, while “bundler” is meant for tools like webpack.

outDir

This is the folder where your compiled .js files will be saved. It is usually ”./dist” or ”./build”.

rootDir

This tells TypeScript where your source files actually start from. It helps map your folder structure, for example: src/ -> dist/

{
"compilerOptions": {
"declaration": true, // Generate .d.ts files for type info
"sourceMap": true, // Generate .map files for debugging
"noImplicitAny": true, // Error if type can't be inferred
"noUnusedLocals": true, // Error on unused variables
"noUnusedParameters": true, // Error on unused function params
"noImplicitReturns": true, // Error if not all code paths return
"allowJs": true, // Allow .js files in project
"checkJs": false, // Disable type checking in .js files
"forceConsistentCasingInFileNames": true, // Error on mismatched import casing
"resolveJsonModule": true, // Allow JSON imports
"esModuleInterop": true, // Compatibility for CommonJS modules
"skipLibCheck": true // Skip type checking of .d.ts files
}
}

These options are not talked about as often, but they can be very helpful once your project grows bigger.

{
"compilerOptions": {
"target": "ES2020",
"module": "CommonJS",
"outDir": "./dist",
"rootDir": "./src",
"strict": true,
"moduleResolution": "node",
"esModuleInterop": true,
"skipLibCheck": true,
"forceConsistentCasingInFileNames": true,
"resolveJsonModule": true,
"declaration": true,
"declarationMap": true,
"sourceMap": true
},
"include": ["src"],
"exclude": ["node_modules", "dist"]
}
{
"compilerOptions": {
"target": "ES2022",
"module": "ESNext",
"outDir": "./dist",
"rootDir": "./src",
"strict": true,
"moduleResolution": "bundler",
"allowJs": true,
"skipLibCheck": true
},
"include": ["src"],
"exclude": ["node_modules", "dist"]
}
Terminal window
# Uses tsconfig.json automatically
npx tsc
# Verbose output to see what's happening
npx tsc --listFiles
Terminal window
npx tsc --watch
# or
npx tsc -w

This is very useful while you are actively coding. The compiler runs automatically every time you save a .ts file, so you do not have to run it by hand each time.

Terminal window
# Even when using tsconfig.json
npx tsc src/main.ts
Terminal window
npx tsc --noEmit

This is useful inside CI/CD pipelines (automated build and test systems), since it lets you catch type errors without actually creating any output files.

Terminal window
npx tsc --showConfig

This shows you the final, combined configuration that TypeScript is actually using.

{
"include": [
"src/**/*", // Everything in src (recursive)
"src/**/*.ts", // Only .ts files
"src/pages/*.ts", // Only files directly in pages/
"src/**/*.{ts,tsx}" // Both .ts and .tsx files
],
"exclude": [
"**/node_modules/**",
"**/dist/**",
"**/*.test.ts",
"**/*.spec.ts"
]
}
{
"include": [
"src/**/*",
"tests/**/*.test.ts"
],
"exclude": [
"node_modules",
"dist",
"build",
".git",
".vscode"
]
}

Check:

  1. Is the file actually inside the include pattern?
  2. Is it being left out by the exclude pattern?
  3. Run this command to see every file being processed: npx tsc --listFiles

Check:

  • Make sure rootDir is correctly pointing to where your source files start.
  • Make sure outDir is pointing to the folder where you actually expect your output.
  • Your file structure should map like this: src/utils/helper.ts -> dist/utils/helper.js

Check:

  • The moduleResolution setting (usually it should be "node" or "bundler")
  • The baseUrl setting, which is used for path mapping
  • The paths configuration, which is used for aliases (shortcuts for import paths)
Terminal window
npx tsc --showConfig -p .

This shows the complete, final configuration that TypeScript is actually using for your project.