TypeScript untuk Pemula: Type Safety di JavaScript


TypeScript adalah superset dari JavaScript yang menambahkan static typing. Dengan TypeScript, kamu bisa menangkap error lebih awal dan menulis kode yang lebih maintainable.

Mengapa TypeScript?

  • Catch errors at compile time: Temukan bug sebelum runtime
  • Better IDE support: Autocomplete dan refactoring lebih baik
  • Self-documenting code: Types sebagai dokumentasi
  • Easier refactoring: Perubahan lebih aman

Setup TypeScript

Instalasi

# Global
npm install -g typescript

# Per project
npm install --save-dev typescript

Inisialisasi

npx tsc --init

Ini akan membuat tsconfig.json:

{
  "compilerOptions": {
    "target": "ES2020",
    "module": "commonjs",
    "strict": true,
    "outDir": "./dist",
    "rootDir": "./src"
  }
}

Compile

npx tsc           # Compile semua
npx tsc --watch   # Watch mode

Basic Types

Primitive Types

// String
let nama: string = 'John';

// Number
let umur: number = 25;
let harga: number = 99.99;

// Boolean
let aktif: boolean = true;

// Null dan Undefined
let kosong: null = null;
let belumAda: undefined = undefined;

Arrays

// Array of strings
let fruits: string[] = ['apple', 'banana', 'orange'];

// Alternative syntax
let numbers: Array<number> = [1, 2, 3];

// Mixed array (tuple)
let person: [string, number] = ['John', 25];

Objects

// Inline type
let user: { name: string; age: number } = {
  name: 'John',
  age: 25,
};

// Optional property
let config: { host: string; port?: number } = {
  host: 'localhost',
};

Any dan Unknown

// Any - hindari jika memungkinkan
let data: any = 'hello';
data = 123; // OK, tapi tidak aman

// Unknown - lebih aman dari any
let input: unknown = 'hello';
if (typeof input === 'string') {
  console.log(input.toUpperCase()); // OK setelah type check
}

Interfaces dan Types

Interface

interface User {
  id: number;
  name: string;
  email: string;
  age?: number; // Optional
  readonly createdAt: Date; // Read-only
}

const user: User = {
  id: 1,
  name: 'John',
  email: 'john@example.com',
  createdAt: new Date(),
};

Type Alias

type ID = string | number;

type Point = {
  x: number;
  y: number;
};

type Status = 'pending' | 'approved' | 'rejected';

Interface vs Type

// Interface - bisa di-extend
interface Animal {
  name: string;
}

interface Dog extends Animal {
  breed: string;
}

// Type - bisa union/intersection
type Cat = Animal & { color: string };
type Pet = Dog | Cat;

Functions

Basic Function Types

// Parameter dan return type
function add(a: number, b: number): number {
  return a + b;
}

// Arrow function
const multiply = (a: number, b: number): number => a * b;

// Optional parameter
function greet(name: string, greeting?: string): string {
  return `${greeting || 'Hello'}, ${name}!`;
}

// Default parameter
function createUser(name: string, role: string = 'user'): void {
  console.log(`Created ${role}: ${name}`);
}

Function Types

// Type untuk function
type MathOperation = (a: number, b: number) => number;

const subtract: MathOperation = (a, b) => a - b;

// Callback
function processData(data: string[], callback: (item: string) => void): void {
  data.forEach(callback);
}

Union dan Intersection Types

Union Types

// Bisa salah satu type
type StringOrNumber = string | number;

function printId(id: StringOrNumber): void {
  if (typeof id === 'string') {
    console.log(id.toUpperCase());
  } else {
    console.log(id);
  }
}

// Literal union
type Direction = 'up' | 'down' | 'left' | 'right';

Intersection Types

interface HasName {
  name: string;
}

interface HasAge {
  age: number;
}

// Gabungan kedua interface
type Person = HasName & HasAge;

const person: Person = {
  name: 'John',
  age: 25,
};

Generics

Basic Generics

// Generic function
function identity<T>(value: T): T {
  return value;
}

const str = identity<string>('hello');
const num = identity<number>(42);

// Type inference
const inferred = identity('hello'); // T = string

Generic Interfaces

interface ApiResponse<T> {
  data: T;
  status: number;
  message: string;
}

interface User {
  id: number;
  name: string;
}

const response: ApiResponse<User> = {
  data: { id: 1, name: 'John' },
  status: 200,
  message: 'Success',
};

Generic Constraints

interface HasLength {
  length: number;
}

function logLength<T extends HasLength>(item: T): void {
  console.log(item.length);
}

logLength('hello'); // OK
logLength([1, 2, 3]); // OK
logLength({ length: 5 }); // OK
// logLength(123);      // Error: number tidak punya length

Classes

class User {
  // Properties
  private id: number;
  public name: string;
  protected email: string;
  readonly createdAt: Date;

  // Constructor
  constructor(id: number, name: string, email: string) {
    this.id = id;
    this.name = name;
    this.email = email;
    this.createdAt = new Date();
  }

  // Method
  public greet(): string {
    return `Hello, ${this.name}!`;
  }

  // Getter
  get userId(): number {
    return this.id;
  }
}

// Inheritance
class Admin extends User {
  private permissions: string[];

  constructor(id: number, name: string, email: string, permissions: string[]) {
    super(id, name, email);
    this.permissions = permissions;
  }

  hasPermission(permission: string): boolean {
    return this.permissions.includes(permission);
  }
}

Utility Types

TypeScript menyediakan utility types bawaan:

interface User {
  id: number;
  name: string;
  email: string;
  password: string;
}

// Partial - semua property jadi optional
type PartialUser = Partial<User>;

// Required - semua property jadi required
type RequiredUser = Required<PartialUser>;

// Pick - ambil property tertentu
type UserPreview = Pick<User, 'id' | 'name'>;

// Omit - hilangkan property tertentu
type PublicUser = Omit<User, 'password'>;

// Readonly - semua property jadi readonly
type ImmutableUser = Readonly<User>;

// Record - object dengan key dan value type tertentu
type UserRoles = Record<string, string[]>;

Type Guards

// typeof guard
function processValue(value: string | number): void {
  if (typeof value === 'string') {
    console.log(value.toUpperCase());
  } else {
    console.log(value.toFixed(2));
  }
}

// instanceof guard
class Dog {
  bark() {
    console.log('Woof!');
  }
}

class Cat {
  meow() {
    console.log('Meow!');
  }
}

function makeSound(animal: Dog | Cat): void {
  if (animal instanceof Dog) {
    animal.bark();
  } else {
    animal.meow();
  }
}

// Custom type guard
interface Fish {
  swim: () => void;
}

interface Bird {
  fly: () => void;
}

function isFish(pet: Fish | Bird): pet is Fish {
  return (pet as Fish).swim !== undefined;
}

Async/Await dengan Types

interface User {
  id: number;
  name: string;
}

// Async function dengan return type
async function fetchUser(id: number): Promise<User> {
  const response = await fetch(`/api/users/${id}`);
  return response.json();
}

// Error handling
async function safeGetUser(id: number): Promise<User | null> {
  try {
    return await fetchUser(id);
  } catch {
    return null;
  }
}

Tips Best Practices

1. Aktifkan Strict Mode

{
  "compilerOptions": {
    "strict": true
  }
}

2. Hindari any

// ❌ Bad
function process(data: any) {}

// ✅ Good
function process<T>(data: T) {}

3. Gunakan Type Inference

// ❌ Redundant
const name: string = 'John';

// ✅ Let TypeScript infer
const name = 'John';

4. Export Types

// types.ts
export interface User {
  id: number;
  name: string;
}

export type Status = 'active' | 'inactive';

Kesimpulan

TypeScript memberikan banyak keuntungan:

  • Error detection lebih awal
  • IDE support yang lebih baik
  • Kode lebih maintainable
  • Dokumentasi otomatis melalui types

Mulai dengan basic types, lalu pelajari generics dan utility types sesuai kebutuhan.


Referensi:

Komentar

Real-time

Memuat komentar...

Tulis Komentar

Email tidak akan ditampilkan

0/2000 karakter

Catatan: Komentar akan dimoderasi sebelum ditampilkan. Mohon bersikap sopan dan konstruktif.