Menu
📱 Lihat versi lengkap (non-AMP)
Programming JavaScript

Cara Belajar TypeScript untuk JavaScript Developer

Editor: Hendra WIjaya
Update: 7 January 2026
Baca: 6 menit

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

Bagikan:

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