Environment, Types & Why TypeScript Exists
Environment, Types & Why TypeScript Exists
TypeScript is JavaScript with a compiler. It catches entire categories of bugs before your code runs, gives you autocomplete on every object, and makes large codebases maintainable.
The Bug TypeScript Prevents
Here is a real JavaScript problem:
// JavaScript — no errors until runtime
function getUser(id) {
return fetch('/api/users/' + id).then(r => r.json())
}
const user = getUser(123)
console.log(user.name.toUpperCase()) // Crashes at runtime: Cannot read properties of undefinedThe issue: fetch is async — user is a Promise, not a User object. JavaScript says nothing. Your app crashes in production.
TypeScript version:
interface User { id: number; name: string }
async function getUser(id: number): Promise<User> {
return fetch('/api/users/' + id).then(r => r.json())
}
const user = getUser(123)
// TypeScript Error: Property 'name' does not exist on type 'Promise<User>'
// You must await the function firstTypeScript catches this before you ever run the code. That is the entire value proposition: move runtime errors to compile time.
VS Code Setup
TypeScript language support is built directly into VS Code — you get syntax highlighting, hover types, and error underlining immediately for any .ts file.
Install one additional extension: ESLint (by Microsoft). Then in your terminal, install the TypeScript ESLint rules for your project:
npm install --save-dev eslint @typescript-eslint/eslint-plugin @typescript-eslint/parserCreate a TypeScript Project
In VS Code, open a new folder. Open the integrated terminal (Ctrl+`) and run:
npm init -y
npm install --save-dev typescript
npx tsc --inittsc --init creates a tsconfig.json with all compiler options. Most are commented out — the defaults are sensible.
tsconfig.json — Key Settings
Open tsconfig.json. The most important options:
{
"compilerOptions": {
"target": "ES2020", // compiled JS version — ES2020 for Node 14+
"module": "commonjs", // module system — commonjs for Node, esnext for bundlers
"strict": true, // enables all strict checks — ALWAYS true
"outDir": "./dist", // compiled JS goes here
"rootDir": "./src", // TypeScript source files are here
"esModuleInterop": true, // makes import/export work cleanly
"skipLibCheck": true // skip type-checking node_modules
},
"include": ["src/**/*"],
"exclude": ["node_modules", "dist"]
}The single most important setting is "strict": true. It enables strictNullChecks (null is separate from other types), noImplicitAny (parameters must have types), and several other checks. Always enable it.
A Multi-File TypeScript Project
Real TypeScript code splits concerns across files. Create this structure:
src/
├── types.ts -- shared interfaces and type aliases
├── utils.ts -- typed utility functions (imports from types.ts)
└── main.ts -- entry point (imports from both)src/types.ts:
export interface User {
id: string
name: string
email: string
role: 'admin' | 'student'
}
export type Status = 'active' | 'inactive' | 'pending'src/utils.ts:
import type { User } from './types'
export function formatUser(user: User): string {
return user.name + ' (' + user.email + ')'
}
export function isAdmin(user: User): boolean {
return user.role === 'admin'
}src/main.ts:
import type { User } from './types'
import { formatUser, isAdmin } from './utils'
const user: User = {
id: 'u_001',
name: 'Jordan Morris',
email: 'jordan@jsupremetech.com',
role: 'admin',
}
console.log(formatUser(user)) // Jordan Morris (jordan@jsupremetech.com)
console.log(isAdmin(user)) // trueThe import type syntax imports only the type — zero JavaScript emitted. Use it for interfaces and type aliases.
Primitive Types and Inference
// Inference — TypeScript figures out the type from the value
const score = 100 // number
const label = 'Pro' // string
const active = true // boolean
// Explicit annotations — required for function parameters
const name: string = 'Jordan'
const age: number = 28
function greet(name: string): string {
return 'Hello, ' + name
}
// Optional parameter
function greetUser(name: string, title?: string): string {
return title ? title + ' ' + name : name
}Annotate function parameters and return types. Let TypeScript infer variable types from assignment.
Compile and Type Check
# Check types — no output files
npx tsc --noEmit
# Compile TypeScript to JavaScript
npx tsc
# Watch mode for development
npx tsc --watchEmpty tsc --noEmit output means zero type errors. Use this in CI to block deployments when types break.