JSTAcademy
0 XP
Dashboard
Crash Courses
Environment, Types & Why TypeScript Exists
12 min
Basic+150 XP
Crash Courses · Basic

Environment, Types & Why TypeScript Exists

See the JS bug TypeScript prevents, set up your project, and understand the type system from zero.
12 min read+150 XP on completionCert: TypeScript Crash Course
Tap any word in the text below to start reading from there.

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 undefined

The 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 first

TypeScript 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/parser

Create 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 --init

tsc --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))      // true

The 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 --watch

Empty tsc --noEmit output means zero type errors. Use this in CI to block deployments when types break.

0%