1. Pengenalan TypeScript
TypeScript adalah bahasa pemrograman open-source yang dikembangkan oleh Microsoft, dibangun di atas JavaScript dengan tambahan sistem tipe statis. TypeScript dikompilasi menjadi JavaScript biasa sehingga bisa berjalan di mana saja β browser, Node.js, Deno, atau Bun.
TypeScript pertama kali dirilis pada tahun 2012 oleh Anders Hejlsberg, arsitek utama bahasa C# dan pencipta Turbo Pascal. Sejak saat itu, TypeScript telah menjadi salah satu bahasa paling populer di dunia pengembangan web, terutama untuk proyek skala besar.
Mengapa Menggunakan TypeScript?
| Keunggulan | Penjelasan |
|---|---|
| Tipe Statis | Mendeteksi error saat development, bukan saat runtime di production |
| Autocompletion | IDE memberikan saran kode yang lebih akurat dan lengkap |
| Refactoring Aman | Mengubah nama fungsi/variabel dengan percaya diri β TypeScript akan menunjukkan semua yang perlu diubah |
| Dokumentasi Hidup | Tipe data berfungsi sebagai dokumentasi yang selalu ter-update |
| Kompatibel 100% | Semua kode JavaScript valid di TypeScript β migrasi bertahap |
| Ekosistem Besar | Definisi tipe tersedia untuk hampir semua library populer (@types/*) |
| Standar Industri | Framework besar seperti Angular, Vue 3, dan Next.js menggunakan TypeScript |
TypeScript vs JavaScript
| Aspek | TypeScript | JavaScript |
|---|---|---|
| Tipe Data | Statis (compile-time) | Dinamis (runtime) |
| Error Detection | Saat kompilasi | Saat eksekusi |
| Interfaces | β Ya | β Tidak ada |
| Generics | β Ya | β Tidak ada |
| Enums | β Ya | β Tidak ada |
| Kompilasi | Perlu di-compile ke JS | Langsung dieksekusi |
| Kurva Belajar | Sedikit lebih curam | Lebih mudah untuk pemula |
Instalasi TypeScript
# Instal TypeScript secara global npm install -g typescript # Cek versi tsc --version # Output: Version 5.x.x # Inisialisasi proyek TypeScript mkdir my-ts-project && cd my-ts-project npm init -y tsc --init # Membuat file tsconfig.json # Compile file TypeScript tsc index.ts # Menghasilkan index.js # Jalankan langsung dengan ts-node (opsional) npx ts-node index.ts
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ β ALUR KERJA TYPESCRIPT β β β β ββββββββββββββββ ββββββββββββββββ ββββββββββββββββββββ β β β .ts files β β Compiler β β .js files β β β β (kode TS βββββΊβ (tsc) βββββΊβ (kode JS β β β β + tipe) β β β β yang valid) β β β ββββββββββββββββ ββββββββ¬ββββββββ ββββββββββββββββββββ β β β β β βΌ β β ββββββββββββββββ β β β tsconfig.jsonβ β Konfigurasi compiler β β ββββββββββββββββ β β β β Error ditemukan DI SINI βββΊ Bukan di production! β βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
2. Tipe Data Dasar
TypeScript menyediakan berbagai tipe data bawaan untuk mendefinisikan struktur data Anda secara eksplisit. Deklarasi tipe menggunakan sintaks : TipeData setelah nama variabel.
Tipe Primitif
// ===== TIPE PRIMITIF =====
// String
let nama: string = "BeebaneLabs";
let salam: string = `Halo, ${nama}!`; // Template literal juga bekerja
// Number (integer dan float menggunakan tipe yang sama)
let umur: number = 25;
let harga: number = 99.99;
let hex: number = 0xff; // Hexadecimal
let binary: number = 0b1010; // Binary
// Boolean
let isActive: boolean = true;
let isLoggedIn: boolean = false;
// Null dan Undefined
let tidakAda: null = null;
let belumDidefinisikan: undefined = undefined;
// Any β menonaktifkan pengecekan tipe (HINDARI penggunaan!)
let apapun: any = "string";
apapun = 42; // OK
apapun = true; // OK β TIDAK ada error!
// Unknown β alternatif yang lebih aman dari any
let tidakDiketahui: unknown = "mungkin string";
// tidakDiketahui.toUpperCase(); // ERROR! Harus di-check dulu
if (typeof tidakDiketahui === "string") {
tidakDiketahui.toUpperCase(); // OK β type narrowing
}
// Void β untuk fungsi yang tidak mengembalikan nilai
function sapa(name: string): void {
console.log(`Halo, ${name}!`);
// Tidak ada return statement
}
// Never β untuk fungsi yang tidak pernah selesai
function throwError(msg: string): never {
throw new Error(msg);
// Kode setelah throw tidak pernah dijalankan
}
Array dan Tuple
// ===== ARRAY =====
let angka: number[] = [1, 2, 3, 4, 5];
let buah: Array<string> = ["apel", "mangga", "jeruk"]; // Generic syntax
// Array campuran β gunakan union type
let campuran: (string | number)[] = [1, "dua", 3, "empat"];
// Readonly array β tidak bisa diubah
let readonlyArr: readonly number[] = [10, 20, 30];
// readonlyArr.push(40); // ERROR! Method push tidak tersedia
// ===== TUPLE =====
// Tuple: array dengan jumlah elemen dan tipe yang tetap
let koordinat: [number, number] = [-6.2088, 106.8456]; // Jakarta
let pengguna: [string, number, boolean] = ["Budi", 28, true];
// Tuple dengan label (labeled tuple) β untuk dokumentasi
type HttpResponse = [statusCode: number, message: string, data: object];
let response: HttpResponse = [200, "OK", { users: [] }];
// Tuple dengan optional element
type FlexTuple = [string, number, boolean?];
let a: FlexTuple = ["hello", 42]; // OK β boolean opsional
let b: FlexTuple = ["hello", 42, true]; // OK
// Destructuring tuple
let [lat, lng] = koordinat;
console.log(`Latitude: ${lat}, Longitude: ${lng}`);
Hindari penggunaan any sebisa mungkin. Gunakan unknown sebagai gantinya karena lebih aman β Anda wajib melakukan type checking sebelum menggunakan nilainya. Gunakan any hanya saat migrasi bertahap dari JavaScript atau saat berinteraksi dengan library lama yang belum ada definisi tipenya.
3. Interfaces & Type Aliases
Interface dan Type Alias adalah dua cara untuk mendefinisikan struktur data kustom di TypeScript. Keduanya sering bisa digunakan secara bergantian, tetapi memiliki perbedaan penting.
Interface Dasar
// ===== INTERFACE =====
interface User {
id: number;
name: string;
email: string;
age?: number; // Opsional (boleh tidak ada)
readonly createdAt: Date; // Readonly β tidak bisa diubah setelah dibuat
}
// Menggunakan interface
const user1: User = {
id: 1,
name: "Budi Santoso",
email: "budi@beebane.com",
createdAt: new Date()
};
// user1.id = 99; // OK β bisa diubah
// user1.createdAt = new Date(); // ERROR! Readonly property
// user1.phone = "081234"; // ERROR! Property tidak didefinisikan
// ===== EXTENDS (PEWARISAN) =====
interface Admin extends User {
role: "admin" | "superadmin"; // Literal type
permissions: string[];
}
const admin1: Admin = {
id: 2,
name: "Admin Utama",
email: "admin@beebane.com",
createdAt: new Date(),
role: "superadmin",
permissions: ["read", "write", "delete", "manage_users"]
};
// ===== INTERFACE MERGING =====
// Interface dengan nama yang sama otomatis di-merge
interface Config {
host: string;
port: number;
}
interface Config {
debug: boolean; // Ditambahkan ke interface Config yang sudah ada
}
// Sekarang Config punya 3 property: host, port, debug
const cfg: Config = {
host: "localhost",
port: 3000,
debug: true
};
Type Alias
// ===== TYPE ALIAS =====
type ID = string | number; // Union type sebagai alias
type Product = {
id: ID;
name: string;
price: number;
category: Category;
};
type Category = "elektronik" | "pakaian" | "makanan" | "minuman";
const laptop: Product = {
id: "PRD-001",
name: "Laptop ASUS ROG",
price: 15000000,
category: "elektronik"
};
// Type alias bisa untuk primitive, union, tuple, dll
type Centimeters = number;
type Point = [x: number, y: number];
type Callback = (data: string) => void;
// Intersection type (menggabungkan beberapa tipe)
type Timestamped = {
createdAt: Date;
updatedAt: Date;
};
type UserWithTimestamp = User & Timestamped;
// Sekarang UserWithTimestamp punya semua property dari User + Timestamped
Interface vs Type Alias
| Fitur | Interface | Type Alias |
|---|---|---|
| Extends/Inheritance | β extends | β Intersection (&) |
| Declaration Merging | β Otomatis merge | β Error jika duplikat |
| Union Type | β Tidak bisa | β Tipe1 | Tipe2 |
| Primitive Alias | β Tidak bisa | β type ID = string |
| Tuple | β Tidak bisa | β type Pair = [a, b] |
| Computed Properties | β Tidak bisa | β mapped types |
| Rekomendasi | Untuk object shapes & API contracts | Untuk union, utility, & tipe kompleks |
4. Generics
Generics memungkinkan Anda menulis kode yang fleksibel dan reusable tanpa mengorbankan type safety. Generics menggunakan parameter tipe (biasanya <T>) yang bisa diisi dengan tipe spesifik saat digunakan.
// ===== GENERICS DASAR =====
// Tanpa generics β harus buat fungsi terpisah untuk tiap tipe
function getFirstNumber(arr: number[]): number {
return arr[0];
}
function getFirstString(arr: string[]): string {
return arr[0];
}
// Dengan generics β SATU fungsi untuk semua tipe!
function getFirst<T>(arr: T[]): T {
return arr[0];
}
const angka = getFirst<number>([10, 20, 30]); // Tipe: number
const teks = getFirst<string>(["a", "b", "c"]); // Tipe: string
// TypeScript otomatis infer tipe juga:
const auto = getFirst([true, false]); // Tipe: boolean
// ===== GENERICS DENGAN CONSTRAINT =====
interface HasLength {
length: number;
}
function logLength<T extends HasLength>(item: T): void {
console.log(`Panjang: ${item.length}`);
}
logLength("hello"); // OK β string punya .length
logLength([1, 2, 3]); // OK β array punya .length
logLength({ length: 10 }); // OK β object punya .length
// logLength(123); // ERROR! number tidak punya .length
// ===== GENERICS DENGAN INTERFACE =====
interface ApiResponse<T> {
status: number;
message: string;
data: T;
timestamp: Date;
}
interface Product {
id: number;
name: string;
price: number;
}
interface User {
id: number;
name: string;
email: string;
}
// Menggunakan generic interface dengan tipe berbeda
const productResponse: ApiResponse<Product> = {
status: 200,
message: "OK",
data: { id: 1, name: "Laptop", price: 10000000 },
timestamp: new Date()
};
const userResponse: ApiResponse<User[]> = {
status: 200,
message: "OK",
data: [
{ id: 1, name: "Budi", email: "budi@test.com" },
{ id: 2, name: "Ani", email: "ani@test.com" }
],
timestamp: new Date()
};
Multiple Type Parameters
// ===== MULTIPLE GENERICS =====
// Fungsi dengan dua type parameter
function merge<T, U>(obj1: T, obj2: U): T & U {
return { ...obj1, ...obj2 };
}
const merged = merge(
{ name: "Budi" },
{ age: 25 }
);
// Tipe: { name: string } & { age: number }
console.log(merged.name); // "Budi"
console.log(merged.age); // 25
// ===== GENERIC CLASS =====
class DataStore<T> {
private items: T[] = [];
add(item: T): void {
this.items.push(item);
}
getById(index: number): T | undefined {
return this.items[index];
}
getAll(): T[] {
return [...this.items];
}
remove(index: number): T | undefined {
return this.items.splice(index, 1)[0];
}
}
// Gunakan dengan tipe spesifik
const userStore = new DataStore<User>();
userStore.add({ id: 1, name: "Budi", email: "budi@test.com" });
const user = userStore.getById(0);
// user otomatis bertipe User | undefined
const numberStore = new DataStore<number>();
numberStore.add(100);
numberStore.add(200);
console.log(numberStore.getAll()); // [100, 200]
// ===== DEFAULT GENERIC =====
interface PaginatedResponse<T = any> {
data: T[];
total: number;
page: number;
pageSize: number;
totalPages: number;
}
// Tanpa parameter β default ke any
const genericResp: PaginatedResponse = {
data: [{ id: 1 }],
total: 100,
page: 1,
pageSize: 10,
totalPages: 10
};
// Dengan parameter β tipe spesifik
const userResp: PaginatedResponse<User> = {
data: [{ id: 1, name: "Budi", email: "budi@test.com" }],
total: 50,
page: 1,
pageSize: 10,
totalPages: 5
};
Gunakan generics saat Anda ingin membuat fungsi, class, atau interface yang bisa bekerja dengan berbagai tipe data tetapi tetap mempertahankan type safety. Contoh nyata: API response wrapper, data store, event handler, dan utility functions.
5. Enums
Enum (enumeration) adalah cara untuk mendefinisikan sekumpulan konstan yang bermakna. TypeScript mendukung numeric enums, string enums, dan heterogenous enums.
// ===== NUMERIC ENUM =====
// Secara default, nilai dimulai dari 0
enum Direction {
Up, // 0
Down, // 1
Left, // 2
Right // 3
}
// Atur nilai awal secara manual
enum HttpStatus {
OK = 200,
Created = 201,
BadRequest = 400,
Unauthorized = 401,
NotFound = 404,
ServerError = 500
}
function handleResponse(status: HttpStatus): void {
switch (status) {
case HttpStatus.OK:
console.log("Berhasil!");
break;
case HttpStatus.NotFound:
console.log("Tidak ditemukan!");
break;
case HttpStatus.ServerError:
console.log("Server error!");
break;
}
}
handleResponse(HttpStatus.OK); // "Berhasil!"
handleResponse(HttpStatus.NotFound); // "Tidak ditemukan!"
// ===== STRING ENUM =====
// Setiap nilai harus diisi secara eksplisit
enum UserRole {
Admin = "ADMIN",
Editor = "EDITOR",
Viewer = "VIEWER",
Guest = "GUEST"
}
enum PaymentMethod {
CreditCard = "CREDIT_CARD",
BankTransfer = "BANK_TRANSFER",
EWallet = "E_WALLET",
Cash = "CASH"
}
// Keunggulan string enum: lebih mudah dibaca saat debugging
console.log(UserRole.Admin); // "ADMIN" (bukan 0)
console.log(PaymentMethod.EWallet); // "E_WALLET" (bukan 2)
// ===== CONST ENUM =====
// Di-inline saat compile β tidak menghasilkan object JS
const enum Color {
Red = "#FF0000",
Green = "#00FF00",
Blue = "#0000FF"
}
const favoriteColor: Color = Color.Blue;
// Compile menjadi: const favoriteColor = "#0000FF";
// Lebih kecil ukuran output, tapi tidak bisa di-iterate
// ===== ENUM SEBAGAI FLAG (Bitwise) =====
enum Permission {
None = 0, // 0000
Read = 1, // 0001
Write = 2, // 0010
Execute = 4, // 0100
Delete = 8 // 1000
}
// Gabungkan permission dengan bitwise OR
let userPerm: Permission = Permission.Read | Permission.Write;
// userPerm = 3 (0011)
// Cek permission dengan bitwise AND
const canRead = (userPerm & Permission.Read) !== 0; // true
const canDelete = (userPerm & Permission.Delete) !== 0; // false
Banyak developer TypeScript senior lebih memilih string literal union type (type Dir = "up" | "down" | "left" | "right") daripada enum karena lebih ringan saat compile dan tidak menghasilkan object JS tambahan. Gunakan enum untuk kasus yang membutuhkan runtime mapping atau bitwise operations.
6. Union Types & Type Assertion
Union type memungkinkan variabel memiliki beberapa tipe sekaligus. Digunakan dengan operator | (pipe). Type assertion memberi tahu compiler bahwa Anda lebih tahu tipe suatu nilai.
// ===== UNION TYPES =====
// Variabel bisa bertipe string ATAU number
let id: string | number;
id = "USR-001"; // OK
id = 42; // OK
// id = true; // ERROR! boolean bukan bagian dari union
// Fungsi yang menerima beberapa tipe
function formatId(id: string | number): string {
if (typeof id === "string") {
return id.toUpperCase(); // TypeScript tahu di sini id = string
}
return `ID-${id.toString().padStart(5, "0")}`; // Di sini id = number
}
console.log(formatId("abc")); // "ABC"
console.log(formatId(42)); // "ID-00042"
// ===== LITERAL TYPES =====
// Tipe yang hanya bisa berisi nilai tertentu
type Theme = "light" | "dark" | "auto";
type StatusCode = 200 | 201 | 400 | 404 | 500;
function setTheme(theme: Theme): void {
document.documentElement.setAttribute("data-theme", theme);
}
setTheme("dark"); // OK
// setTheme("blue"); // ERROR! "blue" bukan bagian dari union
// ===== DISCRIMINATED UNIONS =====
// Pola yang sangat powerful untuk menangani berbagai bentuk data
interface Circle {
kind: "circle"; // Discriminant
radius: number;
}
interface Rectangle {
kind: "rectangle"; // Discriminant
width: number;
height: number;
}
interface Triangle {
kind: "triangle"; // Discriminant
base: number;
height: number;
}
type Shape = Circle | Rectangle | Triangle;
function hitungLuas(shape: Shape): number {
switch (shape.kind) {
case "circle":
return Math.PI * shape.radius ** 2;
case "rectangle":
return shape.width * shape.height;
case "triangle":
return 0.5 * shape.base * shape.height;
}
}
// Exhaustiveness check β memastikan semua case ditangani
const lingkaran: Circle = { kind: "circle", radius: 10 };
console.log(`Luas lingkaran: ${hitungLuas(lingkaran).toFixed(2)}`);
// Luas lingkaran: 314.16
// ===== TYPE ASSERTION =====
// Memberi tahu compiler tentang tipe yang lebih spesifik
// Sintaks "as"
let input: unknown = "Hello TypeScript";
let panjang: number = (input as string).length; // OK
// Sintaks angle bracket (tidak bisa di JSX/TSX)
let panjang2: number = (<string>input).length; // OK di .ts, bukan .tsx
// Non-null assertion (!) β menghapus undefined dan null dari tipe
function findUser(id: number): User | undefined {
return id === 1
? { id: 1, name: "Budi", email: "budi@test.com", createdAt: new Date() }
: undefined;
}
const user = findUser(1);
// user?.name; // OK β optional chaining
const userName = user!.name; // Non-null assertion β Anda YAKIN user tidak undefined
7. Utility Types
TypeScript menyediakan berbagai utility types bawaan untuk memanipulasi tipe β membuat tipe baru dari tipe yang sudah ada tanpa perlu menulis ulang definisi lengkap.
// Base interface untuk contoh-contoh berikut
interface Product {
id: number;
name: string;
price: number;
description: string;
category: string;
inStock: boolean;
}
// ===== Partial<T> β Semua property jadi opsional =====
type PartialProduct = Partial<Product>;
// { id?: number; name?: string; price?: number; ... }
function updateProduct(id: number, updates: Partial<Product>): void {
// updates hanya berisi field yang ingin diubah
console.log(`Update product ${id}:`, updates);
}
updateProduct(1, { price: 150000 }); // OK β hanya update price
// ===== Required<T> β Semua property jadi wajib =====
type RequiredProduct = Required<Product>;
// ===== Readonly<T> β Semua property jadi readonly =====
type ReadonlyProduct = Readonly<Product>;
// ===== Pick<T, K> β Pilih beberapa property saja =====
type ProductSummary = Pick<Product, "id" | "name" | "price">;
// { id: number; name: string; price: number; }
const summary: ProductSummary = {
id: 1,
name: "Laptop",
price: 10000000
};
// ===== Omit<T, K> β Hapus beberapa property =====
type ProductWithoutPrice = Omit<Product, "price" | "description">;
// { id: number; name: string; category: string; inStock: boolean; }
// ===== Record<K, V> β Membuat tipe object dengan key dan value =====
type UserRoles = Record<string, string[]>;
const roles: UserRoles = {
admin: ["read", "write", "delete"],
editor: ["read", "write"],
viewer: ["read"]
};
// Lebih spesifik dengan literal types
type ProductMap = Record<number, Product>;
const products: ProductMap = {
1: { id: 1, name: "Laptop", price: 10000000, description: "...", category: "elektronik", inStock: true },
2: { id: 2, name: "Mouse", price: 150000, description: "...", category: "elektronik", inStock: false }
};
// ===== Exclude<T, U> & Extract<T, U> =====
type AllTypes = string | number | boolean | null | undefined;
type NonNullableTypes = Exclude<AllTypes, null | undefined>;
// string | number | boolean
type OnlyStringNumber = Extract<AllTypes, string | number>;
// string | number
// ===== ReturnType<T> β Ambil tipe return dari fungsi =====
function createUser() {
return {
id: 1,
name: "Budi",
email: "budi@test.com",
createdAt: new Date()
};
}
type NewUser = ReturnType<typeof createUser>;
// { id: number; name: string; email: string; createdAt: Date }
// ===== Parameters<T> β Ambil tipe parameter dari fungsi =====
function greet(name: string, greeting: string): string {
return `${greeting}, ${name}!`;
}
type GreetParams = Parameters<typeof greet>;
// [name: string, greeting: string]
Anda juga bisa membuat utility types sendiri! Misalnya type Nullable<T> = T | null atau type DeepReadonly<T> yang membuat semua property nested menjadi readonly. Kombinasikan dengan mapped types dan conditional types untuk manipulasi tipe yang lebih powerful.
8. Konfigurasi tsconfig.json
File tsconfig.json adalah konfigurasi utama TypeScript compiler. Di sini Anda mengatur target JavaScript output, strict mode, module system, dan berbagai opsi lainnya.
{
"compilerOptions": {
// ===== TARGET & MODULE =====
"target": "ES2022", // Target versi JavaScript output
"module": "ESNext", // Module system (ESNext, CommonJS, AMD)
"moduleResolution": "bundler", // Cara resolve import (bundler, node)
"lib": ["ES2022", "DOM", "DOM.Iterable"],
// ===== STRICT MODE (SANGAT DIREKOMENDASIKAN!) =====
"strict": true, // Aktifkan SEMUA strict checks
// Atau secara manual:
// "noImplicitAny": true, // Error jika tipe any tersembunyi
// "strictNullChecks": true, // null/undefined harus eksplisit
// "strictFunctionTypes": true,
// "strictBindCallApply": true,
// "strictPropertyInitialization": true,
// ===== OUTPUT =====
"outDir": "./dist", // Folder output JavaScript
"rootDir": "./src", // Folder sumber TypeScript
"sourceMap": true, // Generate source map untuk debugging
"declaration": true, // Generate .d.ts declaration files
"declarationMap": true, // Source map untuk declaration files
// ===== ADDITIONAL CHECKS =====
"noUnusedLocals": true, // Error jika ada variabel yang tidak dipakai
"noUnusedParameters": true, // Error jika ada parameter yang tidak dipakai
"noImplicitReturns": true, // Error jika fungsi tidak return di semua path
"noFallthroughCasesInSwitch": true,
"forceConsistentCasingInFileNames": true,
// ===== INTEROP =====
"esModuleInterop": true, // Kompatibilitas CommonJS/ES Module
"allowSyntheticDefaultImports": true,
"isolatedModules": true, // Kompatibel dengan bundler (Vite, esbuild)
"resolveJsonModule": true, // Bisa import file .json
"skipLibCheck": true, // Skip pengecekan file .d.ts
// ===== PATH ALIASES =====
"baseUrl": ".",
"paths": {
"@/*": ["./src/*"],
"@components/*": ["./src/components/*"],
"@utils/*": ["./src/utils/*"]
}
},
"include": ["src/**/*"], // File yang di-compile
"exclude": ["node_modules", "dist"] // File yang diabaikan
}
Opsi Penting yang Perlu Diketahui
| Opsi | Default | Penjelasan |
|---|---|---|
| strict | false | Aktifkan semua strict checks β WAJIB true untuk proyek baru |
| target | ES3 | Target JS output β gunakan ES2020+ untuk fitur modern |
| module | CommonJS | Module system β gunakan ESNext untuk Vite/modern bundler |
| outDir | ./ | Folder output JS β pisahkan dari source |
| sourceMap | false | Generate source map β aktifkan untuk debugging |
| esModuleInterop | false | Kompatibilitas import β aktifkan untuk menghindari masalah |
| noUnusedLocals | false | Error jika ada variabel tidak dipakai β bantu menjaga kebersihan kode |
9. Migrasi dari JavaScript
TypeScript dirancang untuk mendukung migrasi bertahap dari JavaScript. Anda tidak perlu mengubah semua file sekaligus β mulai dari file yang paling kritis dan tambahkan tipe secara bertahap.
Langkah 1: Pasang TypeScript
# Di proyek JavaScript yang sudah ada npm install --save-dev typescript @types/node # Buat tsconfig.json npx tsc --init # Ubah pengaturan agar JS dan TS bisa berdampingan: # "allowJs": true, β Izinkan file .js # "checkJs": true, β Cek tipe di file .js juga (opsional) # "outDir": "./dist", # "strict": false β Mulai dengan false, aktifkan bertahap
Langkah 2: Rename Bertahap
proyek-saya/ βββ src/ β βββ utils/ β β βββ helpers.js β Tahap 1: Biarkan .js β β βββ validators.js β Tahap 2: Rename jadi .ts β β βββ format.ts β Tahap 3: Sudah .ts dengan tipe lengkap β βββ components/ β β βββ Button.jsx β React: rename ke .tsx β β βββ Modal.tsx β Sudah TypeScript β βββ app.ts β Entry point sudah TypeScript βββ tsconfig.json βββ package.json
Langkah 3: Pola Migrasi Umum
// ===== SEBELUM (JavaScript) =====
// utils.js
function formatCurrency(amount, currency) {
return new Intl.NumberFormat('id-ID', {
style: 'currency',
currency: currency || 'IDR'
}).format(amount);
}
function calculateDiscount(price, discountPercent) {
return price - (price * discountPercent / 100);
}
module.exports = { formatCurrency, calculateDiscount };
// ===== SESUDAH (TypeScript) =====
// utils.ts
type Currency = "IDR" | "USD" | "EUR" | "JPY";
interface FormatOptions {
currency?: Currency;
locale?: string;
}
function formatCurrency(
amount: number,
options: FormatOptions = {}
): string {
const { currency = "IDR", locale = "id-ID" } = options;
return new Intl.NumberFormat(locale, {
style: "currency",
currency
}).format(amount);
}
function calculateDiscount(price: number, discountPercent: number): number {
if (discountPercent < 0 || discountPercent > 100) {
throw new Error("Diskon harus antara 0 dan 100");
}
return price - (price * discountPercent / 100);
}
export { formatCurrency, calculateDiscount };
export type { Currency, FormatOptions };
// ===== MENAMBAHKAN TIPE KE LIBRARY LAMA =====
// Jika library tidak punya @types, buat file deklarasi:
// types/my-old-lib.d.ts
declare module "my-old-lib" {
export function doSomething(input: string): number;
export function doOther(a: number, b: number): string;
export const VERSION: string;
}
- Mulai dengan
strict: false, lalu aktifkan satu per satu - Gunakan
// @ts-ignoreuntuk sementara melewati error (tapi jangan terlalu banyak!) - Install
@types/*untuk library yang digunakan - Mulai dari file yang paling sering di-edit atau punya bug
- Gunakan
anysementara lalu ganti dengan tipe yang benar - Aktifkan
allowJs: trueagar .js dan .ts bisa berdampingan
10. Quiz: Uji Pemahamanmu!
Setelah membaca tutorial di atas, jawablah 5 pertanyaan berikut untuk menguji pemahamanmu tentang TypeScript: