10 TypeScript Tips yang Bikin Kode Anda Lebih Bersih dan Aman di 2026
TypeScript sudah jadi standar di industri. Tapi banyak developer masih pakai TypeScript seperti JavaScript biasa. Ini 10 tips advanced yang benar-benar berguna di project nyata.
Muhamad Putra Aulia Hidayat
10 TypeScript Tips untuk Kode yang Lebih Bersih
Setelah hampir 2 tahun TypeScript jadi standar wajib di hampir semua project JavaScript serius, masih banyak developer yang belum menggunakannya secara optimal. Ini tips-tips yang benar-benar berguna.
1. Pakai satisfies bukan Type Assertion
// Buruk - as mematikan type checking
const config = {
theme: "dark",
port: 3000
} as AppConfig
// Lebih baik - satisfies tetap check tipe tapi pertahankan literal types
const config = {
theme: "dark",
port: 3000
} satisfies AppConfig
// Sekarang config.theme bertipe "dark" bukan string
2. Discriminated Union untuk State Management
// Buruk
interface ApiState {
loading: boolean
data?: User
error?: string
}
// Baik - setiap state eksplisit dan type-safe
type ApiState =
| { status: "idle" }
| { status: "loading" }
| { status: "success"; data: User }
| { status: "error"; error: string }
function render(state: ApiState) {
switch (state.status) {
case "success":
return state.data.name // TypeScript tahu data ada di sini
case "error":
return state.error // TypeScript tahu error ada di sini
}
}
3. Template Literal Types
type HttpMethod = "GET" | "POST" | "PUT" | "DELETE"
type ApiRoute = "/users" | "/products" | "/orders"
type ApiEndpoint = `${HttpMethod} ${ApiRoute}`
// TypeScript akan autocomplete: "GET /users", "POST /products", dll
function callApi(endpoint: ApiEndpoint) { ... }
4. Infer dalam Conditional Types
// Extract return type dari promise
type Awaited<T> = T extends Promise<infer R> ? R : T
// Extract parameter types
type FirstParam<T extends (...args: any) => any> =
T extends (first: infer F, ...rest: any) => any ? F : never
// Contoh penggunaan
async function fetchUser(): Promise<User> { ... }
type UserType = Awaited<ReturnType<typeof fetchUser>> // User
5. Mapped Types untuk Transformasi
// Buat semua property opsional tapi hanya satu level
type PartialOne<T> = { [K in keyof T]?: T[K] }
// Buat semua property readonly dan required
type Frozen<T> = { readonly [K in keyof T]-?: T[K] }
// Buat type baru dengan rename key
type Getters<T> = {
[K in keyof T as `get${Capitalize<string & K>}`]: () => T[K]
}
interface User { name: string; age: number }
type UserGetters = Getters<User>
// { getName: () => string; getAge: () => number }
6. Const Assertions untuk Config
// Tanpa const assertion
const ROLES = ["admin", "user", "moderator"]
// Tipe: string[]
// Dengan const assertion
const ROLES = ["admin", "user", "moderator"] as const
// Tipe: readonly ["admin", "user", "moderator"]
type Role = typeof ROLES[number]
// Tipe: "admin" | "user" | "moderator"
7. Branded Types untuk Keamanan
// Masalah: ID yang berbeda tapi sama-sama string
function getUser(userId: string) { ... }
function getProduct(productId: string) { ... }
// Tidak ada yang cegah: getUser(productId) -- bug!
// Solusi: Branded types
type UserId = string & { readonly __brand: "UserId" }
type ProductId = string & { readonly __brand: "ProductId" }
function createUserId(id: string): UserId {
return id as UserId
}
function getUser(userId: UserId) { ... }
// getUser(productId) sekarang error TypeScript!
8. Exhaustive Checks
type Shape = "circle" | "square" | "triangle"
function getArea(shape: Shape, size: number): number {
switch (shape) {
case "circle": return Math.PI * size ** 2
case "square": return size ** 2
case "triangle": return (Math.sqrt(3) / 4) * size ** 2
default:
// Kalau ada Shape baru yang belum di-handle, TypeScript error di sini
const _exhaustive: never = shape
throw new Error(`Unhandled shape: ${_exhaustive}`)
}
}
9. Pakai unknown bukan any
// Buruk - any mematikan semua type checking
function processData(data: any) {
data.nonExistentMethod() // Tidak ada error, bug tersembunyi
}
// Baik - unknown paksa kamu validasi dulu
function processData(data: unknown) {
if (typeof data === "object" && data !== null && "name" in data) {
console.log((data as { name: string }).name)
}
}
10. Strict Mode Full
Pastikan tsconfig.json kamu punya:
{
"compilerOptions": {
"strict": true,
"noUncheckedIndexedAccess": true,
"exactOptionalPropertyTypes": true,
"noImplicitReturns": true,
"noFallthroughCasesInSwitch": true
}
}
strict: true saja tidak cukup — noUncheckedIndexedAccess sangat berguna untuk mencegah bug saat akses array/object dengan index dinamis.
Semua tips di atas sudah kami terapkan di semua project Digital Uptime. Hasilnya: lebih sedikit bug di production dan onboarding developer baru jadi lebih mudah.
Newsletter Digital Uptime
Tips teknologi & bisnis mingguan
Bergabung dengan 2,500+ subscriber yang mendapatkan insight teknologi, tutorial development, dan tips bisnis digital langsung ke inbox mereka setiap minggu.