Skip to content

Setting Up TypeScript

TypeScript can be installed globally or as a project dependency.

Terminal window
# Install globally (not recommended for projects)
npm install -g typescript
# Install as a project dependency (recommended)
npm install --save-dev typescript
# Verify the installation
npx tsc --version
# Output: Version 5.x.x

Recommendation: Always install TypeScript as a devDependency per project. This ensures every developer uses the same version.


Create a tsconfig.json file to configure the TypeScript compiler:

Terminal window
# Generate a default tsconfig.json
npx tsc --init

This creates a tsconfig.json with sensible defaults. For a new project, start with this configuration:

{
"compilerOptions": {
"target": "ES2022",
"module": "ESNext",
"moduleResolution": "bundler",
"strict": true,
"esModuleInterop": true,
"skipLibCheck": true,
"forceConsistentCasingInFileNames": true,
"outDir": "./dist",
"rootDir": "./src"
},
"include": ["src/**/*.ts"],
"exclude": ["node_modules", "dist"]
}

Every option in tsconfig.json controls how TypeScript behaves:

OptionPurposeRecommended
targetWhich JS version to compile toES2022 or ESNext
moduleModule system for outputESNext, CommonJS, or NodeNext
strictEnable all strict type checkstrue
outDirOutput directory for compiled JS./dist
rootDirSource directory./src

When strict: true is enabled, these individual checks are turned on:

FlagWhat It Does
noImplicitAnyError when TypeScript can’t infer a type
strictNullChecksnull and undefined are only assignable to unknown, any, and their respective types
strictFunctionTypesEnables stricter checking of function types
strictBindCallApplyChecks arguments to bind, call, apply
strictPropertyInitializationClass properties must be initialized in constructor
noImplicitThisError when this has an implicit any type
alwaysStrictAlways emit "use strict"

A typical TypeScript project structure:

my-project/
├── src/
│ ├── index.ts # Entry point
│ ├── types/
│ │ └── index.ts # Shared type definitions
│ ├── utils/
│ │ ├── helpers.ts
│ │ └── validation.ts
│ └── services/
│ └── api.ts
├── dist/ # Compiled output (gitignored)
├── tests/
│ └── index.test.ts
├── tsconfig.json
├── package.json
└── .gitignore

Terminal window
# Compile once
npx tsc
# Compile in watch mode (recompiles on changes)
npx tsc --watch
# Check types without emitting files
npx tsc --noEmit
# Compile a single file
npx tsc src/index.ts --outDir dist
# Compile with a specific config file
npx tsc --project tsconfig.json

{
"scripts": {
"build": "tsc",
"watch": "tsc --watch",
"typecheck": "tsc --noEmit",
"clean": "rm -rf dist"
}
}

Terminal window
npm install --save-dev eslint @typescript-eslint/parser @typescript-eslint/eslint-plugin
.eslintrc.json
{
"parser": "@typescript-eslint/parser",
"plugins": ["@typescript-eslint"],
"extends": [
"eslint:recommended",
"plugin:@typescript-eslint/recommended"
],
"rules": {
"@typescript-eslint/no-explicit-any": "warn",
"@typescript-eslint/explicit-function-return-type": "off"
}
}

Project Architecture: TypeScript Compilation

Section titled “Project Architecture: TypeScript Compilation”
flowchart LR
TSSRC[.ts Source Files<br/>src/] --> TSC[TypeScript Compiler<br/>tsc --noEmit]
TSSRC --> BUILD[Build Tool<br/>tsc / esbuild / vite]
TSC -->|Type Check ✅| CLEAN[Type-safe Code]
BUILD --> JS[.js Output<br/>dist/]
JS --> DEPLOY[Deploy to<br/>Browser / Node]
TSCONFIG[tsconfig.json<br/>Configures everything] -.-> TSC
TSCONFIG -.-> BUILD
style TSSRC fill:#7c3aed,color:#fff
style TSC fill:#3b82f6,color:#fff
style BUILD fill:#f59e0b,color:#fff
style JS fill:#059669,color:#fff
style TSCONFIG fill:#ec4899,color:#fff
style DEPLOY fill:#10b981,color:#fff

Flow: Write .ts in src/ → tsc checks types (in CI: --noEmit) → build tool emits .js to dist/ → deploy. The tsconfig.json file is the control panel that tells everything how to behave.

Vite:

Terminal window
npm create vite@latest my-app -- --template react-ts

Webpack:

Terminal window
npm install --save-dev ts-loader
webpack.config.js
module.exports = {
entry: './src/index.ts',
module: {
rules: [
{ test: /\.tsx?$/, use: 'ts-loader', exclude: /node_modules/ }
]
},
resolve: { extensions: ['.tsx', '.ts', '.js'] }
};

VS Code has built-in TypeScript support. Key features:

FeatureShortcut
Go to DefinitionF12
Find ReferencesShift + F12
Rename SymbolF2
Quick FixCtrl + .
Type HintsHover over variable
Auto ImportType and select from suggestions

Enable these in settings.json:

{
"typescript.updateImportsOnFileMove.enabled": "always",
"typescript.suggest.autoImports": true,
"typescript.preferences.importModuleSpecifier": "relative"
}

MistakeFix
Installing TypeScript globallyUse npm install --save-dev typescript per project
Not using strict: trueEnables critical type safety checks
Ignoring tsconfig.json errorsFix configuration before coding
Mixing module systemsMatch module to your bundler’s requirements

  1. Always use strict: true in tsconfig.json
  2. Add build, watch, and typecheck scripts to package.json
  3. Run tsc --noEmit in CI to prevent type errors from reaching production
  4. Keep rootDir and outDir separate so compiled JS doesn’t pollute source
  5. Use .gitignore to exclude dist/ and node_modules/

Easy: How do you create a new TypeScript project from scratch?

Medium: What does strict: true enable in tsconfig.json?

Hard: Explain the difference between target, module, and moduleResolution in tsconfig.json and when you’d use each.