# Cheat Sheet: Jebakan Frustasi TypeScript

TypeScript memang powerful, tapi ada beberapa "jebakan" yang bisa bikin frustasi. Berikut daftarnya beserta solusinya:

---

## **1\. Type Inference yang Menyesatkan**

**Masalah**: TypeScript kadang infer tipe yang tidak diharapkan.

```typescript
const arr = [1, 2, "3"]; // inferred as (number | string)[]
```

**Solusi**: Gunakan type annotation eksplisit.

```typescript
const arr: number[] = [1, 2, 3]; // Error jika ada string
```

---

## **2\.** `any` yang Diam-diam Menyusup

**Masalah**: `any` menghilangkan type safety.

```typescript
let data: any = "Hello";
data = 42; // No error, tapi bahaya!
```

**Solusi**: Hindari `any`, gunakan `unknown` atau type yang lebih spesifik.

```typescript
let data: unknown = "Hello";
if (typeof data === "string") {
  console.log(data.toUpperCase()); // Safe
}
```

---

## **3\. Optional vs Null/Undefined**

**Masalah**: Bingung antara `?`, `null`, dan `undefined`.

```typescript
interface User {
  name?: string; // Optional property
}
const user: User = {};
console.log(user.name?.toUpperCase()); // OK
console.log(user.name.toUpperCase()); // Error: mungkin undefined
```

**Solusi**: Pahami perbedaannya:

* `?` = Properti opsional (bisa `undefined`).
    
* `null` = Nilai eksplisit `null`.
    
* `undefined` = Tidak ada nilai.
    

---

## **4\. Type Narrowing yang Tidak Berfungsi**

**Masalah**: TypeScript tidak selalu menyempitkan tipe dengan benar.

```typescript
function isString(x: any): x is string {
  return typeof x === "string";
}
let value: string | number = "Hello";
if (isString(value)) {
  console.log(value.toUpperCase()); // OK
} else {
  console.log(value.toFixed(2)); // Error: mungkin string
}
```

**Solusi**: Gunakan type guards yang lebih eksplisit (`typeof`, `instanceof`, dll).

---

## **5\.** `readonly` yang Tidak Sepenuhnya Immutable

**Masalah**: `readonly` hanya berlaku di level terluar.

```typescript
interface Config {
  readonly apiUrl: string;
  readonly endpoints: string[];
}
const config: Config = { apiUrl: "...", endpoints: ["/a", "/b"] };
config.endpoints.push("/c"); // Tidak error!
```

**Solusi**: Gunakan `ReadonlyArray` atau `DeepReadonly` (dengan utility type/library).

```typescript
interface Config {
  readonly apiUrl: string;
  readonly endpoints: ReadonlyArray<string>;
}
```

---

## **6\. Overloading Function yang Membingungkan**

**Masalah**: Overload signature bisa rumit.

```typescript
function greet(name: string): string;
function greet(age: number): string;
function greet(value: any): string {
  return typeof value === "string" ? `Hello, ${value}` : `Age: ${value}`;
}
```

**Solusi**: Gunakan union types jika memungkinkan.

```typescript
function greet(value: string | number): string {
  return typeof value === "string" ? `Hello, ${value}` : `Age: ${value}`;
}
```

---

## **7\.** `this` Context yang Hilang

**Masalah**: `this` bisa berubah di callback.

```typescript
class Button {
  onClick() {
    console.log("Clicked!");
  }
  addListener() {
    document.addEventListener("click", this.onClick); // `this` bukan instance Button!
  }
}
```

**Solusi**: Gunakan arrow function atau `.bind(this)`.

```typescript
class Button {
  onClick = () => {
    console.log("Clicked!");
  };
  addListener() {
    document.addEventListener("click", this.onClick); // Works!
  }
}
```

---

## **8\. Generics yang Terlalu Kompleks**

**Masalah**: Generics bisa bikin kode sulit dibaca.

```typescript
function merge<T, U>(a: T, b: U): T & U {
  return { ...a, ...b };
}
```

**Solusi**: Gunakan default type atau batasi dengan constraints.

```typescript
function merge<T extends object, U extends object>(a: T, b: U): T & U {
  return { ...a, ...b };
}
```

---

## **9\. Module Resolution yang Membingungkan**

**Masalah**: Import bisa error karena `moduleResolution` tidak sesuai.

```typescript
// Error jika `moduleResolution: "node"` dan file tidak ada
import { something } from "./file.ts";
```

**Solusi**: Pahami konfigurasi `tsconfig.json` (`"node"`, `"classic"`, dll).

---

## **10\. Strict Null Checks yang Ketat**

**Masalah**: `strictNullChecks` bisa bikin banyak error.

```typescript
let name: string;
name = null; // Error jika `strictNullChecks: true`
```

**Solusi**: Gunakan union type (`string | null`) atau optional chaining (`?.`).

---

### **Kesimpulan**

* Selalu aktifkan `strict: true` di `tsconfig.json`.
    
* Hindari `any`, gunakan `unknown` atau type yang lebih spesifik.
    
* Pahami perbedaan `null`, `undefined`, dan optional properties.
    
* Gunakan type guards untuk narrowing.
    
* Hati-hati dengan mutability (`readonly`, `const`, `ReadonlyArray`).
    

Semoga cheat sheet ini membantu menghindari jebakan TypeScript! 🚀
