Salin dan Bagikan
Cara Belajar TypeScript untuk JavaScript Developer - Panduan lengkap belajar TypeScript untuk developer yang sudah familiar dengan JavaScript

Cara Belajar TypeScript untuk JavaScript Developer

TypeScript adalah superset JavaScript yang menambahkan static typing. Mari pelajari cara menggunakannya.

Apa itu TypeScript?

Keuntungan TypeScript

- Type safety (catch errors early)
- Better IDE support (autocomplete)
- Self-documenting code
- Refactoring lebih aman
- Better tooling
- Growing adoption

TypeScript vs JavaScript

// JavaScript
function add(a, b) {
  return a + b;
}
add("1", 2); // "12" (string concatenation)

// TypeScript
function add(a: number, b: number): number {
  return a + b;
}
add("1", 2); // Error: Argument of type 'string' not assignable

Setup

Install TypeScript

# Global installation
npm install -g typescript

# Project installation
npm init -y
npm install typescript --save-dev

# Initialize tsconfig
npx tsc --init

tsconfig.json

{
  "compilerOptions": {
    "target": "ES2020",
    "module": "commonjs",
    "lib": ["ES2020"],
    "outDir": "./dist",
    "rootDir": "./src",
    "strict": true,
    "esModuleInterop": true,
    "skipLibCheck": true,
    "forceConsistentCasingInFileNames": true,
    "resolveJsonModule": true,
    "declaration": true,
    "declarationMap": true,
    "sourceMap": true
  },
  "include": ["src/**/*"],
  "exclude": ["node_modules", "dist"]
}

Compile dan Run

# Compile
npx tsc

# Watch mode
npx tsc --watch

# Run with ts-node
npm install -g ts-node
ts-node src/index.ts

Basic Types

Primitive Types

// String
let nama: string = "Budi";

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

// Boolean
let aktif: boolean = true;

// Any (avoid if possible)
let data: any = "could be anything";

// Unknown (safer than any)
let input: unknown = "something";

// Void (function returns nothing)
function log(message: string): void {
  console.log(message);
}

// Null dan Undefined
let nullable: null = null;
let undef: undefined = undefined;

Arrays

// Array of numbers
let numbers: number[] = [1, 2, 3];

// Alternative syntax
let strings: Array<string> = ["a", "b", "c"];

// Mixed array with tuple
let tuple: [string, number] = ["Budi", 25];

// Array of objects
let users: { name: string; age: number }[] = [
  { name: "Budi", age: 25 },
  { name: "Ani", age: 23 },
];

Objects

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

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

// Readonly
let point: { readonly x: number; readonly y: number } = {
  x: 10,
  y: 20,
};
// point.x = 5; // Error: Cannot assign to 'x'

Type Aliases dan Interfaces

Type Alias

// Basic type alias
type ID = string | number;

// Object type alias
type User = {
  id: ID;
  name: string;
  email: string;
  age?: number;
};

// Union type
type Status = "pending" | "approved" | "rejected";

// Function type
type MathFunc = (a: number, b: number) => number;

const add: MathFunc = (a, b) => a + b;

Interface

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

// Extend interface
interface Admin extends User {
  role: string;
  permissions: string[];
}

// Implement interface
class AdminUser implements Admin {
  id: number;
  name: string;
  email: string;
  role: string;
  permissions: string[];

  constructor(data: Admin) {
    this.id = data.id;
    this.name = data.name;
    this.email = data.email;
    this.role = data.role;
    this.permissions = data.permissions;
  }
}

Type vs Interface

// Interface: can be extended/merged
interface User {
  name: string;
}
interface User {
  age: number;
}
// User now has both name and age

// Type: can use union/intersection
type StringOrNumber = string | number;
type Combined = User & { email: string };

// Recommendation:
// - Use interface untuk objects
// - Use type untuk unions, primitives, tuples

Functions

Function Types

// Parameter dan return types
function greet(name: string): string {
  return `Hello, ${name}!`;
}

// Arrow function
const add = (a: number, b: number): number => a + b;

// Optional parameters
function createUser(name: string, age?: number): User {
  return { name, age: age || 0 };
}

// Default parameters
function greet(name: string = "World"): string {
  return `Hello, ${name}!`;
}

// Rest parameters
function sum(...numbers: number[]): number {
  return numbers.reduce((a, b) => a + b, 0);
}

Function Overloading

function format(value: string): string;
function format(value: number): string;
function format(value: string | number): string {
  if (typeof value === "string") {
    return value.toUpperCase();
  }
  return value.toFixed(2);
}

console.log(format("hello")); // "HELLO"
console.log(format(3.14159)); // "3.14"

Generics

Basic Generics

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

const str = identity<string>("hello");
const num = identity<number>(42);
const inferred = identity("hello"); // Type inferred

// Generic array
function firstElement<T>(arr: T[]): T | undefined {
  return arr[0];
}

Generic Interfaces

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

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

const userResponse: ApiResponse<User> = {
  data: { id: 1, name: "Budi" },
  status: 200,
  message: "Success",
};

Generic Constraints

interface HasLength {
  length: number;
}

function logLength<T extends HasLength>(arg: T): number {
  console.log(arg.length);
  return arg.length;
}

logLength("hello"); // 5
logLength([1, 2, 3]); // 3
// logLength(123);      // Error: number doesn't have length

Utility Types

Built-in Utility Types

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

// Partial - all properties optional
type PartialUser = Partial<User>;

// Required - all properties required
type RequiredUser = Required<PartialUser>;

// Pick - select properties
type UserPreview = Pick<User, "id" | "name">;

// Omit - exclude properties
type UserWithoutPassword = Omit<User, "password">;

// Readonly - all properties readonly
type ReadonlyUser = Readonly<User>;

// Record - create object type
type UserRoles = Record<string, string[]>;
const roles: UserRoles = {
  admin: ["read", "write", "delete"],
  user: ["read"],
};

Conditional Types

type IsString<T> = T extends string ? "yes" : "no";

type A = IsString<string>; // "yes"
type B = IsString<number>; // "no"

// Extract dan Exclude
type T1 = Extract<"a" | "b" | "c", "a" | "f">; // "a"
type T2 = Exclude<"a" | "b" | "c", "a">; // "b" | "c"

Classes

Class with Types

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

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

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

  // Getter
  get displayName(): string {
    return this.name.toUpperCase();
  }

  // Setter
  set displayName(value: string) {
    this.name = value;
  }
}

Abstract Classes

abstract class Animal {
  constructor(public name: string) {}

  abstract makeSound(): string;

  move(): void {
    console.log(`${this.name} is moving`);
  }
}

class Dog extends Animal {
  makeSound(): string {
    return "Woof!";
  }
}

Type Guards

Type Narrowing

function printValue(value: string | number) {
  if (typeof value === "string") {
    console.log(value.toUpperCase()); // TypeScript knows it's string
  } else {
    console.log(value.toFixed(2)); // TypeScript knows it's number
  }
}

// instanceof
class Dog {
  bark() {
    console.log("Woof!");
  }
}
class Cat {
  meow() {
    console.log("Meow!");
  }
}

function makeSound(animal: Dog | Cat) {
  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;
}

Modules

Export dan Import

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

export function createUser(name: string): User {
  return { id: Date.now(), name };
}

export default class UserService {
  // ...
}

// main.ts
import UserService, { User, createUser } from "./user";

const user: User = createUser("Budi");

Type-only Imports

import type { User } from "./user";
import { type User, createUser } from "./user";

Error Handling

Typed Errors

class AppError extends Error {
  constructor(message: string, public code: string, public statusCode: number) {
    super(message);
    this.name = "AppError";
  }
}

function fetchUser(id: number): User {
  if (id < 0) {
    throw new AppError("Invalid ID", "INVALID_ID", 400);
  }
  // ...
}

try {
  fetchUser(-1);
} catch (error) {
  if (error instanceof AppError) {
    console.log(error.code, error.statusCode);
  }
}

Best Practices

Do’s

// Use strict mode
"strict": true

// Prefer interfaces for objects
interface User { ... }

// Use const assertions
const colors = ["red", "green", "blue"] as const;

// Use unknown instead of any
function parse(input: unknown) { ... }

// Explicit return types for public APIs
export function getUser(id: number): User { ... }

Don’ts

// Avoid any
let data: any; // ❌

// Avoid type assertions when possible
const user = data as User; // ❌ if avoidable

// Avoid non-null assertions
user!.name; // ❌ prefer optional chaining

// Don't ignore errors
// @ts-ignore // ❌

Kesimpulan

TypeScript meningkatkan developer experience dengan type safety dan better tooling. Start dengan basics, gradually add more advanced types seiring kebutuhan.

Artikel Terkait

Link Postingan : https://www.tirinfo.com/cara-belajar-typescript-javascript/

Hendra WIjaya
Tirinfo
6 minutes.
7 January 2026