TypeScript Fundamentals: From Basic Types to Advanced Patterns
Basic Types
TypeScript adds static typing to JavaScript, making code more maintainable and catching errors at compile time rather than runtime.
'use strict'
let username: string = "hello"
let count: number = 42
let isActive: boolean = false
let empty: null = null
let pending: undefined = undefined
let optionalValue: string | null = null
// Type assertion for narrowing
let numbers = [10, 20, 30]
const result = numbers.find(item => item > 15) as number
console.log(result * 2)
Complex Types
Arrays
let numericList: number[] = [1, 2, 3]
let stringList: Array<string> = ['x', 'y', 'z']
Tuples
Tuples allow defining arrays with fixed types at specific positions.
let record: [number, string, boolean] = [1, 'data', true]
let partial: [number, string, number?] = [1, 'data'] // last element optional
Enums
enum Direction {
Up,
Down,
Left,
Right
}
console.log(Direction.Up) // 0
console.log(Direction[0]) // 'Up'
Functions
function processData(
id: number,
label: string,
enabled?: boolean, // optional parameter
...tags: number[] // rest parameters
): void {
console.log(id, label)
}
processData(100, 'test', true, 1, 2, 3)
Interfaces
interface UserProfile {
username: string
age: number
}
const user1: UserProfile = {
username: 'alice',
age: 25
}
const user2: UserProfile = {
username: 'bob',
age: 30
}
Type Aliases
For reducing repetition with union types.
type UserId = string | number
let id1: UserId = 'user-001'
let id2: UserId = 1001
Generics
Generics provide type safety for functions that work with multiple types.
function combine<T>(first: T, second: T): T[] {
return [first, second]
}
combine<number>(1, 2) // valid
combine<string>('a', 'b') // valid
combine<number | string>(1, 'a') // valid
combine<number>(1, 'a') // error: type mismatch
Advanced Concepts
Interface Inheritance
interface Vehicle {
wheels: number
speed: number
}
interface Car extends Vehicle {
brand: string
}
const myCar: Car = {
wheels: 4,
speed: 120,
brand: 'Tesla'
}
Classes
class Article {
title: string
body: string
category?: string // optional property
views = 0 // default value
private draft?: string
protected metadata?: object
static readonly publisher: string = 'TechPress'
constructor(title: string, body: string) {
this.title = title
this.body = body
}
}
class BlogPost extends Article {
constructor(title: string, body: string) {
super(title, body)
this.metadata // accessible: protected allows subclass access
}
}
const post = new Article('Intro', 'Content here')
// post.draft // error: private, only accessible within Article
// post.metadata // error: protected, only accessible within Article or subclasses
// Article.publisher // static: accessed via class, not instance
Accessors
class Account {
private _token: string = ''
get token(): string {
return '********'
}
set token(newToken: string) {
this._token = newToken
}
}
const account = new Account()
account.token = 'abc123'
console.log(account.token) // displays: ********
Abstract Classes
Abstract classes define contracts without direct instantiation.
abstract class Shape {
abstract color: string
abstract calculateArea(): number
display(): void {
console.log('Rendering shape')
}
}
class Circle extends Shape {
color: string = 'blue'
radius: number = 5
calculateArea(): number {
return Math.PI * this.radius ** 2
}
}
Implementing Interfaces
Unlike inheritance, a class can implement multpile interfaces.
interface Named {
name: string
}
interface Describable {
describe(): string
}
interface Aged {
years: number
}
class Person implements Named, Aged {
name: string = 'John'
years: number = 28
describe(): string {
return `${this.name} is ${this.years} years old`
}
}
Gneerics in Classes
class Container<T> {
private data: T
constructor(initial: T) {
this.data = initial
}
transform(input: T): T {
console.log('Processing:', this.data)
return input
}
}
const textContainer = new Container<string>('world')
textContainer.transform('hello')
const numContainer = new Container<number>(999)
numContainer.transform(100)