September 28, 2026
Dasar TypeScript.
Fondasi TypeScript: tipe primitif, array & tuple, interface vs type, union & intersection, literal type, dan type narrowing — dengan contoh yang bisa langsung dijalankan.
TypeScript adalah JavaScript + sistem tipe statis. Semua kode JavaScript yang valid adalah TypeScript yang valid, tapi TypeScript menambahkan anotasi tipe yang dicek saat compile — bukan saat runtime. Hasil akhirnya tetap JavaScript biasa; tipe dihapus total ketika kode dijalankan.
Keuntungannya praktis: autocomplete yang akurat, refactor yang aman, dan bug seperti undefined is not a function tertangkap sebelum sampai ke user.
1. Menjalankan TypeScript
Cara tercepat mencoba tanpa setup proyek:
mkdir belajar-ts && cd belajar-ts
npm init -y
npm install -D typescript
npx tsc --init # membuat tsconfig.json
Buat index.ts, lalu:
npx tsc --noEmit # hanya cek tipe, tidak menghasilkan .js
node index.ts # Node.js 22.18+ / 23.6+ bisa menjalankan .ts langsung (type stripping)
Node.js versi baru menjalankan file
.tsdengan cara membuang anotasi tipe saja — ia tidak mengecek tipe. Pengecekan tetap tugastsc. Jadi alurnya:tsc --noEmituntuk validasi, runtime untuk eksekusi.
2. Tipe Dasar
let nama: string = "Fanny";
let umur: number = 27;
let aktif: boolean = true;
let kosong: null = null;
let belumAda: undefined = undefined;
// Type inference: anotasi sering tidak perlu
let kota = "Semarang"; // otomatis string
// kota = 10; // ❌ Type 'number' is not assignable to type 'string'
| Tipe | Contoh | Catatan |
|---|---|---|
string, number, boolean | "a", 42, true | Pakai huruf kecil, bukan String/Number |
T[] / Array<T> | string[] | Array dengan elemen sejenis |
| Tuple | [string, number] | Panjang & urutan tetap |
any | — | Mematikan pengecekan, hindari |
unknown | — | Versi aman dari any: wajib dicek dulu sebelum dipakai |
never | — | Nilai yang tidak mungkin ada (mis. fungsi yang selalu throw) |
void | — | Fungsi tanpa nilai kembalian |
const tags: string[] = ["ts", "js"];
const koordinat: [number, number] = [-6.99, 110.42];
function gagal(pesan: string): never {
throw new Error(pesan);
}
function log(pesan: string): void {
console.log(pesan);
}
Fungsi
function tambah(a: number, b: number): number {
return a + b;
}
// Parameter opsional & default
function sapa(nama: string, salam = "Halo", titik?: string) {
return `${salam}, ${nama}${titik ?? "!"}`;
}
// Tipe fungsi sebagai nilai
const kali: (a: number, b: number) => number = (a, b) => a * b;
Sintaks arrow function tetap sama; TypeScript hanya menambah anotasi pada parameter dan nilai kembalian.
3. Object: interface vs type
Dua cara mendeskripsikan bentuk objek:
interface User {
id: number;
nama: string;
email?: string; // opsional
readonly createdAt: Date; // tidak bisa diubah setelah dibuat
}
type Produk = {
id: number;
nama: string;
harga: number;
};
const u: User = { id: 1, nama: "Fanny", createdAt: new Date() };
// u.createdAt = new Date(); // ❌ read-only
Perbedaannya:
| Aspek | interface | type |
|---|---|---|
| Bentuk objek | ✅ | ✅ |
| Union / primitif / tuple | ❌ | ✅ (type Id = string | number) |
| Extend | interface B extends A {} | type B = A & { ... } |
| Declaration merging | ✅ (deklarasi dua kali digabung) | ❌ (error duplikat) |
| Pesan error | Biasanya menampilkan nama interface | Kadang diekspansi |
interface Admin extends User {
role: "admin";
}
type AdminT = User & { role: "admin" };
Aturan praktis: pakai interface untuk bentuk objek publik (props, model data) dan type untuk union, alias, dan komposisi. Yang penting konsisten dalam satu proyek.
4. Union & Intersection
Union (A | B) artinya “salah satu dari”:
type Id = string | number;
function cetakId(id: Id) {
console.log(`ID: ${id}`);
}
cetakId(10);
cetakId("abc-123");
Literal type membuat union sangat berguna — nilainya dibatasi ke string tertentu:
type Status = "draft" | "published" | "archived";
function ubahStatus(s: Status) { /* ... */ }
ubahStatus("published"); // ✅
// ubahStatus("deleted"); // ❌ tidak ada di union
Intersection (A & B) artinya “gabungan semua properti”:
type Timestamps = { createdAt: Date; updatedAt: Date };
type Artikel = { judul: string; isi: string } & Timestamps;
const a: Artikel = {
judul: "Belajar TS",
isi: "...",
createdAt: new Date(),
updatedAt: new Date(),
};
5. Type Narrowing
Saat nilai bertipe union, TypeScript memaksa kita mempersempit tipenya sebelum memakai method khusus. Narrowing terjadi otomatis dari pengecekan runtime biasa.
typeof, truthiness, in, instanceof
function format(nilai: string | number | null) {
if (nilai === null) return "-"; // equality narrowing
if (typeof nilai === "string") {
return nilai.toUpperCase(); // di sini: string
}
return nilai.toFixed(2); // di sini: number
}
type Kucing = { meong(): void };
type Anjing = { gonggong(): void };
function suara(hewan: Kucing | Anjing) {
if ("meong" in hewan) hewan.meong(); // in narrowing
else hewan.gonggong();
}
function pesanError(e: unknown) {
if (e instanceof Error) return e.message; // instanceof narrowing
return String(e);
}
Discriminated union
Pola paling berguna di TypeScript: setiap anggota union punya properti “penanda” (biasanya type atau kind).
type Hasil =
| { status: "loading" }
| { status: "sukses"; data: string[] }
| { status: "error"; pesan: string };
function render(h: Hasil): string {
switch (h.status) {
case "loading":
return "Memuat...";
case "sukses":
return h.data.join(", "); // data hanya ada di sini
case "error":
return `Gagal: ${h.pesan}`;
default: {
const _cek: never = h; // exhaustiveness check
return _cek;
}
}
}
Jika nanti ada status baru (mis. "kosong") dan lupa ditangani, baris const _cek: never = h langsung error. Ini jaring pengaman yang sangat berharga saat refactor.
Custom type guard
interface Produk { id: number; harga: number }
function isProduk(x: unknown): x is Produk {
return (
typeof x === "object" && x !== null &&
"id" in x && "harga" in x
);
}
const data: unknown = JSON.parse('{"id":1,"harga":5000}');
if (isProduk(data)) {
console.log(data.harga * 2); // data: Produk
}
6. as, satisfies, dan Non-null !
// Type assertion: "percayalah, saya tahu tipenya" — tidak ada pengecekan runtime
const input = document.querySelector("#email") as HTMLInputElement;
// satisfies: cek kecocokan TANPA melebarkan tipe
const warna = {
primer: "#b45309",
sekunder: [180, 83, 9],
} satisfies Record<string, string | number[]>;
warna.primer.toUpperCase(); // ✅ tetap dikenal sebagai string
warna.sekunder.map((n) => n); // ✅ tetap number[]
// Non-null assertion: buang null/undefined (hati-hati)
const el = document.getElementById("app")!;
| Operator | Kapan dipakai |
|---|---|
as T | Data dari DOM/API yang tipenya kita tahu pasti |
satisfies T | Objek konfigurasi: ingin divalidasi tapi tetap tipe spesifik |
! | Hanya jika benar-benar yakin tidak null |
Kesalahan Umum
- Memakai
anysupaya error hilang.anymenular: semua yang menyentuhnya ikut kehilangan tipe. Gunakanunknownlalu narrowing. - Mengira tipe ada di runtime.
interfacetidak bisa dicek denganinstanceof; data dari API tetap perlu divalidasi (type guard atau library seperti Zod). asuntuk “memaksa” tipe yang salah.{} as Userlolos compile tapi akan crash saat properti diakses. Assertion bukan konversi.- Terlalu banyak anotasi.
const x: number = 5berlebihan — biarkan inference bekerja, anotasi cukup di parameter fungsi dan batas modul. - Pakai
String/Number/Object(huruf besar). Itu tipe wrapper object, bukan primitif. - Lupa exhaustiveness check pada discriminated union, sehingga case baru terlewat diam-diam.
- Menyalahgunakan
!. Non-null assertion hanya memindahkan error dari compile-time ke runtime.
Ringkasan
- TypeScript = JavaScript + tipe yang dicek saat compile, lalu dihapus.
interfaceuntuk bentuk objek,typeuntuk union dan komposisi.- Union + literal type + discriminated union adalah kombinasi paling produktif.
- Narrowing terjadi lewat
typeof,in,instanceof, equality, dan type guard. - Lanjut ke Generics & Utility Types untuk membuat tipe yang reusable.

Hey! I’m Fanny, the software engineer tending to this digital garden. You can read more about me, or subscribe by email.