Masukkan Password
84 Bekerja dengan Namespace
Lecture ini adalah praktik langsung penggunaan namespace TypeScript untuk memecah kode menjadi beberapa file, kemudian menggabungkan hasil compile-nya menjadi satu file JavaScript (bundle.js).
Kalau lecture sebelumnya menjelaskan konsep besarnya, lecture ini menunjukkan masalah nyata yang muncul dan bagaimana outFile + namespace menyelesaikannya.
1. Gambaran besar dulu
Target akhirnya adalah seperti ini:
DEVELOPMENT
│
┌──────────┴──────────┐
↓ ↓
app.ts user-action.ts
│ │
│ │
└──────────┬──────────┘
↓
TypeScript Compiler
↓
bundle.js
↓
HTML
Jadi saat development, kita punya beberapa file:
app.ts
user-action.ts
Tetapi saat compile, kita ingin:
bundle.js
yang berisi kode dari kedua file tersebut.
2. Kenapa kita ingin melakukan ini?
Bayangkan project semakin besar.
Daripada:
app.ts
↓
5000 baris
kita pecah:
app.ts
user-action.ts
product-action.ts
payment.ts
validation.ts
utils.ts
Masing-masing file menjadi lebih kecil dan mudah dikelola.
Tetapi browser nantinya tidak harus diberi banyak file JavaScript.
Kita bisa menghasilkan:
bundle.js
yang berisi semuanya.
Jadi ada dua kebutuhan:
Saat development
Kita ingin:
Banyak file agar kode rapi.
Saat browser menjalankan aplikasi
Kita ingin:
Satu file bundle agar lebih sederhana untuk dimuat.
3. Membuat user-action.ts
Lecture membuat file baru:
src/
├── app.ts
└── user-action.ts
Kemudian di user-action.ts dibuat namespace:
namespace UserAction {
}
Ingat:
namespace UserAction
adalah sebuah wadah bernama UserAction.
Di dalamnya kita dapat meletakkan:
- class
- function
- variable
- interface
- dan sebagainya.
4. Membuat class User
Di dalam namespace:
namespace UserAction {
class User {
constructor(
public name: string,
public age: number,
public gender: string
) {}
}
}
Class ini memiliki:
User
├── name: string
├── age: number
└── gender: string
Karena menggunakan parameter properties:
constructor(
public name: string,
public age: number,
public gender: string
) {}
TypeScript secara otomatis membuat property.
Kurang lebih konsepnya sama seperti:
class User {
public name: string;
public age: number;
public gender: string;
constructor(
name: string,
age: number,
gender: string
) {
this.name = name;
this.age = age;
this.gender = gender;
}
}
Jadi syntax constructor pendek tadi hanya shorthand.
5. Membuat userList
Kemudian lecture membuat:
const userList: User[] = [];
Perhatikan bahwa ini bukan property class.
Ini adalah variable yang berada di dalam namespace.
Strukturnya:
UserAction namespace
│
├── User class
│
└── userList
userList memiliki tipe:
User[]
Artinya:
Array yang hanya boleh berisi object
User.
Awalnya:
[]
kosong.
6. Membuat function createUser
Kemudian:
function createUser(
name: string,
age: number,
gender: string
) {
const user = new User(name, age, gender);
userList.push(user);
return user;
}
Mari kita bedah.
Langkah 1 — menerima data
Function menerima:
name: string
age: number
gender: string
Misalnya:
createUser("John", 28, "male");
Maka:
name = "John"
age = 28
gender = "male"
Langkah 2 — membuat object User
const user = new User(name, age, gender);
Hasilnya:
User {
name: "John",
age: 28,
gender: "male"
}
Langkah 3 — masukkan ke array
userList.push(user);
Sekarang:
userList
│
└── User("John", 28, "male")
Kalau kita membuat user kedua:
createUser("Mary", 30, "female");
menjadi:
userList
├── User("John", 28, "male")
└── User("Mary", 30, "female")
Langkah 4 — return user
return user;
Jadi kita juga bisa mendapatkan object yang baru dibuat:
const u1 = createUser("John", 28, "male");
7. Membuat function getUsers
Kemudian:
function getUsers() {
return userList;
}
Function ini sederhana.
Tugasnya:
Mengembalikan seluruh user yang sudah dibuat.
Misalnya:
createUser("John", 28, "male");
createUser("Mary", 30, "female");
Kemudian:
getUsers();
menghasilkan:
[
User("John", 28, "male"),
User("Mary", 30, "female")
]
8. Struktur user-action.ts
Jadi secara konsep:
UserAction
│
├── User
│
├── userList
│
├── createUser()
│
└── getUsers()
Ini sudah menjadi satu kelompok yang masuk akal:
Semua berkaitan dengan user.
9. Kenapa function harus export?
Sekarang muncul masalah.
Kita punya:
user-action.ts
dan:
app.ts
createUser() berada di:
user-action.ts
Tetapi kita ingin memanggilnya dari:
app.ts
Kalau kita hanya menulis:
function createUser() {
// ...
}
function tersebut tidak otomatis dapat digunakan dari luar namespace.
Maka kita menggunakan:
export function createUser() {
// ...
}
dan:
export function getUsers() {
// ...
}
10. Apa arti export?
Sederhananya:
export= “Saya mengizinkan bagian ini digunakan dari luar.”
Misalnya:
namespace UserAction {
class User {
// ...
}
export function createUser() {
// ...
}
export function getUsers() {
// ...
}
}
Maka:
UserAction
│
├── User
│ ❌ tidak diexport
│
├── createUser()
│ ✅ export
│
└── getUsers()
✅ export
Artinya app.ts dapat menggunakan:
createUser()
getUsers()
tetapi tidak secara langsung menggunakan User dari luar namespace jika User tidak di-export.
11. export tidak hanya untuk function
Ini juga penting.
Kita bisa melakukan:
export class User {}
atau:
export const something = 10;
atau:
export interface UserData {}
Jadi secara umum:
export
├── function
├── class
├── variable
├── interface
└── ...
Apa pun yang ingin digunakan dari luar namespace dapat di-export.
12. Sekarang bagaimana app.ts menggunakan namespace?
Ini bagian yang agak unik dari namespace TypeScript.
Kita perlu memberitahu TypeScript:
“File
app.tsmembutuhkan fileuser-action.ts.”
Caranya menggunakan:
/// <reference path="./user-action.ts" />
Perhatikan ada tiga slash:
///
bukan:
//
13. Apa itu /// <reference path="..." />?
Ini disebut triple-slash directive.
Contohnya:
/// <reference path="./user-action.ts" />
Maksud sederhananya:
“TypeScript, tolong jadikan file
user-action.tssebagai referensi/dependency untuk file ini.”
Path:
./user-action.ts
berarti:
File
user-action.tsberada di folder yang sama dengan file saat ini.
Misalnya:
src/
├── app.ts
└── user-action.ts
maka:
./user-action.ts
benar.
14. Kenapa tidak cukup memanggil createUser()?
Misalnya di app.ts:
createUser("John", 28, "male");
TypeScript akan bingung.
Karena createUser sebenarnya berada di:
UserAction
Jadi kita perlu berada dalam namespace yang sama.
15. Namespace harus memiliki nama yang sama
Di user-action.ts:
namespace UserAction {
// ...
}
Di app.ts juga:
namespace UserAction {
}
Kenapa?
Karena namespace dengan nama yang sama akan dianggap sebagai bagian dari namespace yang sama.
Secara konsep:
user-action.ts
namespace UserAction {
export function createUser() {}
}
dan:
app.ts
namespace UserAction {
const u1 = createUser(...);
}
menjadi seperti satu namespace:
UserAction
│
├── createUser()
├── getUsers()
├── User
├── userList
└── code dari app.ts
Ini adalah salah satu karakteristik penting namespace TypeScript.
16. Analogi puzzle 🧩
Bayangkan ada dua potongan puzzle.
File pertama:
user-action.ts
┌─────────────────────┐
│ UserAction │
│ │
│ createUser() │
│ getUsers() │
│ User │
└─────────────────────┘
File kedua:
app.ts
┌─────────────────────┐
│ UserAction │
│ │
│ menggunakan │
│ createUser() │
│ getUsers() │
└─────────────────────┘
Karena namanya sama:
UserAction
TypeScript menganggap keduanya sebagai bagian dari namespace yang sama.
17. Membuat app.ts
Kurang lebih:
/// <reference path="./user-action.ts" />
namespace UserAction {
const u1 = createUser("John", 28, "male");
const u2 = createUser("Mary", 30, "female");
console.log(u1);
console.log(u2);
console.log(getUsers());
}
Sekarang TypeScript dapat menemukan:
createUser()
dan:
getUsers()
karena:
user-action.tsdireferensikan.- Keduanya berada dalam namespace
UserAction. - Function tersebut di-
export.
18. Sampai sini TypeScript senang
Ketika compile:
app.ts
user-action.ts
↓
TypeScript Compiler
↓
berhasil
TypeScript memahami hubungan:
app.ts
│
│ reference
↓
user-action.ts
Tetapi kemudian muncul masalah baru.
19. Masalah besar: JavaScript tidak memiliki konsep namespace TypeScript
Misalnya TypeScript menghasilkan:
dist/
├── app.js
└── user-action.js
HTML hanya memasukkan:
<script src="app.js"></script>
Nah, masalahnya:
TypeScript
↓
mengerti namespace
↓
UserAction
tetapi JavaScript hasil compile:
app.js
tidak otomatis memuat:
user-action.js
20. Ini yang menyebabkan error
Bayangkan app.js berisi kode yang secara konsep ingin melakukan:
UserAction.createUser(...)
Tetapi browser hanya memuat:
app.js
Sedangkan:
user-action.js
tidak pernah dimuat.
Maka browser tidak mengetahui definisi yang diperlukan.
Hasilnya error seperti:
createUser is not a function
atau error terkait UserAction.
21. Kenapa TypeScript tidak otomatis menyelesaikannya?
Ini adalah inti masalah lecture.
TypeScript compiler memahami namespace dan reference directive.
Tetapi browser hanya menjalankan JavaScript.
Browser tidak tahu:
"oh, app.ts punya reference ke user-action.ts"
Itu adalah informasi untuk TypeScript compiler, bukan mekanisme module loading JavaScript modern.
Jadi:
TypeScript world
↓
namespace + reference
↓
TypeScript mengerti
tetapi:
Browser world
↓
JavaScript files
↓
tidak otomatis memahami hubungan namespace tadi
22. Solusi lecture: buat satu file JavaScript
Daripada menghasilkan:
app.js
user-action.js
kita ingin:
bundle.js
yang berisi:
compiled app.ts
+
compiled user-action.ts
Sehingga:
bundle.js
│
├── compiled user-action.ts
└── compiled app.ts
Sekarang browser hanya perlu memuat:
<script src="bundle.js"></script>
23. Di sinilah outFile digunakan
Buka:
tsconfig.json
Kemudian ada property:
"outFile": "./dist/bundle.js"
Artinya:
“TypeScript, jangan membuat satu JavaScript output untuk setiap
.tsfile. Gabungkan output JavaScript-nya menjadi satu file bernamabundle.js.”
24. Sebelum outFile
Misalnya:
src/
├── app.ts
└── user-action.ts
Compile menghasilkan:
dist/
├── app.js
└── user-action.js
25. Setelah menggunakan outFile
Dengan:
{
"compilerOptions": {
"outFile": "./dist/bundle.js"
}
}
hasilnya menjadi:
dist/
└── bundle.js
Isi bundle.js secara konsep:
bundle.js
│
├── JavaScript hasil compile user-action.ts
│
└── JavaScript hasil compile app.ts
26. Tapi muncul error lagi: module
Lecture kemudian mendapatkan error:
Only AMD and System modules are supported alongside
outFile.
Ini sebenarnya menunjukkan bahwa outFile mempunyai persyaratan tertentu.
Misalnya sebelumnya:
"module": "commonjs"
Tidak bisa digunakan bersama outFile untuk skenario ini.
Lecture kemudian menggantinya menjadi:
"module": "amd"
atau:
"module": "system"
27. Apa itu AMD/System?
Untuk tahap lecture ini, kamu tidak perlu memahami detail internal AMD atau SystemJS terlebih dahulu.
Cukup pahami hubungan berikut:
outFile
+
module
↓
harus menggunakan module format
yang didukung untuk bundling ini
Dalam contoh lecture:
"module": "amd"
sehingga outFile dapat digunakan.
Catatan penting: ini adalah pola legacy TypeScript namespace. Untuk project modern, kamu akan lebih sering menemukan ES modules (
import/export) + bundler daripadanamespace+outFile.
28. Setelah bundle.js dibuat
Sebelumnya HTML:
<script src="app.js"></script>
Sekarang app.js tidak lagi menjadi output utama.
Kita ubah menjadi:
<script src="bundle.js"></script>
Sekarang alurnya:
HTML
│
│ <script src="bundle.js">
↓
bundle.js
│
├── UserAction
├── createUser()
├── getUsers()
└── app code
Semuanya ada dalam satu file.
29. Sekarang createUser() berhasil
Di app.ts:
const u1 = createUser("John", 28, "male");
const u2 = createUser("Mary", 30, "female");
Kemudian:
console.log(u1);
console.log(u2);
Hasilnya kurang lebih:
User {
name: "John",
age: 28,
gender: "male"
}
User {
name: "Mary",
age: 30,
gender: "female"
}
30. getUsers() juga berhasil
Kemudian:
console.log(getUsers());
menghasilkan array:
[
User {
name: "John",
age: 28,
gender: "male"
},
User {
name: "Mary",
age: 30,
gender: "female"
}
]
Jadi semua fungsi dari user-action.ts dapat digunakan dari app.ts.
31. Perhatikan konsep “development vs production”
Ini sebenarnya inti dari semuanya.
Saat development, kita ingin:
src/
├── app.ts
├── user-action.ts
├── product-action.ts
├── validation.ts
└── ...
Kenapa?
Karena mudah dikelola.
Tetapi setelah compile, dengan pendekatan lecture:
dist/
└── bundle.js
Kenapa?
Karena browser cukup mendapatkan satu file.
32. Diagram keseluruhan lecture
Ini bagian yang sangat bagus untuk kamu hafalkan:
SOURCE CODE
│
┌──────────┴──────────┐
↓ ↓
app.ts user-action.ts
│ │
│ │
└──────────┬──────────┘
│
namespace
UserAction
│
↓
TypeScript Compiler
│
outFile
│
↓
bundle.js
│
↓
HTML
│
↓
Browser
33. Apa peran masing-masing bagian?
| Bagian | Fungsi |
|---|---|
namespace | Mengelompokkan kode |
export | Membuka kode agar dapat digunakan dari bagian lain |
/// <reference path> | Memberitahu TypeScript tentang file yang direferensikan |
outFile | Menggabungkan hasil compile menjadi satu file |
bundle.js | File JavaScript gabungan |
HTML <script> | Memuat JavaScript ke browser |
34. Contoh kode lengkap versi sederhana
user-action.ts
namespace UserAction {
class User {
constructor(
public name: string,
public age: number,
public gender: string
) {}
}
const userList: User[] = [];
export function createUser(
name: string,
age: number,
gender: string
) {
const user = new User(name, age, gender);
userList.push(user);
return user;
}
export function getUsers() {
return userList;
}
}
app.ts
/// <reference path="./user-action.ts" />
namespace UserAction {
const u1 = createUser("John", 28, "male");
const u2 = createUser("Mary", 30, "female");
console.log(u1);
console.log(u2);
console.log(getUsers());
}
tsconfig.json
Konsep konfigurasi lecture:
{
"compilerOptions": {
"outFile": "./dist/bundle.js",
"module": "amd"
}
}
Tentunya tsconfig.json milik project bisa memiliki property lain juga.
HTML
<script src="./dist/bundle.js"></script>
35. Kenapa User tidak perlu di-export?
Perhatikan:
class User {
...
}
bukan:
export class User {
...
}
Karena app.ts tidak membutuhkan User secara langsung.
app.ts hanya membutuhkan:
createUser()
getUsers()
Maka:
export function createUser()
export function getUsers()
sudah cukup.
Ini prinsip yang bagus:
Export hanya apa yang memang perlu digunakan oleh bagian lain.
Jangan sembarang membuat semuanya public/export kalau tidak diperlukan.
36. Hal yang sering bikin bingung: namespace vs class
Namespace:
namespace UserAction {
}
bukan class.
Namespace adalah wadah untuk mengelompokkan kode.
Di dalam namespace bisa ada:
namespace
│
├── class
├── function
├── variable
├── interface
└── ...
Sedangkan class:
class User {
}
adalah blueprint untuk membuat object.
Jadi:
namespace UserAction
↓
pengelompokan kode
class User
↓
blueprint object
Fungsinya berbeda.
37. Hal yang sangat penting: namespace tidak sama dengan ES6 module
Ini jangan sampai tertukar.
Namespace
namespace UserAction {
export function createUser() {}
}
dan biasanya menggunakan:
/// <reference path="./user-action.ts" />
ES6 Module
// user-action.ts
export function createUser() {}
kemudian:
// app.ts
import { createUser } from "./user-action";
Tidak menggunakan:
/// <reference path="..." />
Jadi:
Namespace
→ namespace
→ reference directive
→ outFile
sedangkan:
ES6 Modules
→ import/export
→ module dependency
→ bisa dibundle dengan bundler
38. Kenapa lecture memilih namespace?
Karena section ini memang sedang mengajarkan:
Bagaimana namespace bekerja dalam TypeScript.
Lecture ingin menunjukkan bahwa namespace memungkinkan kita:
- memecah kode menjadi banyak file,
- mengelompokkan kode,
- menggunakan
export, - menghubungkan file dengan
reference, - kemudian menggabungkan hasil compile menggunakan
outFile.
39. Satu detail penting tentang urutan file
Karena namespace + outFile menggabungkan beberapa file menjadi satu file JavaScript, urutan file/dependency menjadi penting.
Misalnya:
user-action.ts
harus tersedia sebelum code yang bergantung padanya digunakan.
Itulah salah satu alasan pendekatan module modern menjadi lebih nyaman: dependency dinyatakan secara eksplisit dengan:
import ...
dan tooling modern menangani dependency graph tersebut.
40. Kenapa pendekatan ini terasa agak “aneh”?
Kalau kamu sudah pernah melihat JavaScript modern, mungkin kamu berpikir:
“Kenapa tidak langsung
importdanexportsaja?”
Jawabannya:
Karena lecture ini sedang mengajarkan pendekatan namespace TypeScript, yang merupakan pendekatan lebih lama.
Jadi jangan heran kalau syntax-nya terasa berbeda.
Dalam development modern, kamu akan lebih sering melihat:
import { User } from "./user";
daripada:
/// <reference path="./user.ts" />
Tetapi memahami namespace tetap berguna untuk memahami codebase TypeScript lama dan sejarah perkembangan module system TypeScript.
41. Mental model paling sederhana 🧠
Bayangkan namespace sebagai sebuah gedung.
UserAction
┌────────────────────────────┐
│ │
│ User │
│ │
│ userList │
│ │
│ createUser() ← export │
│ │
│ getUsers() ← export │
│ │
└────────────────────────────┘
export berarti:
“Pintu ini boleh digunakan dari luar.”
app.ts masuk ke gedung yang sama:
UserAction
┌────────────────────────────┐
│ │
│ createUser("John", 28...) │
│ getUsers() │
│ │
└────────────────────────────┘
Kemudian TypeScript menggabungkan seluruh gedung tersebut menjadi:
bundle.js
dan browser cukup membuka:
<script src="bundle.js"></script>
42. Alur eksekusi sebenarnya
Mari kita urutkan dari awal sampai akhir.
Step 1 — Developer memecah kode
app.ts
user-action.ts
Step 2 — Buat namespace
namespace UserAction {}
Step 3 — Masukkan kode ke namespace
User
userList
createUser()
getUsers()
Step 4 — Export bagian yang dibutuhkan
export function createUser()
export function getUsers()
Step 5 — Reference file
/// <reference path="./user-action.ts" />
Step 6 — app.ts menggunakan function
createUser(...)
getUsers()
Step 7 — Atur outFile
"outFile": "./dist/bundle.js"
Step 8 — Compile
TS files
↓
TypeScript Compiler
↓
bundle.js
Step 9 — HTML load bundle
<script src="bundle.js"></script>
Step 10 — Browser menjalankan seluruh aplikasi
bundle.js
↓
UserAction
↓
createUser()
↓
getUsers()
43. Ringkasan yang wajib kamu ingat
Kalau mau mengingat lecture ini dengan sangat singkat:
namespace
Wadah untuk mengelompokkan kode.
export
Membuat bagian namespace dapat digunakan dari luar.
/// <reference path="..." />
Memberitahu TypeScript bahwa file lain harus dijadikan referensi.
outFile
Menggabungkan hasil compile beberapa TypeScript file menjadi satu JavaScript file.
bundle.js
File JavaScript hasil gabungan yang kemudian dimuat oleh HTML.
Cheat sheet 📝
namespace
│
┌────────────┼────────────┐
↓ ↓ ↓
class function variable
│
export
↓
bisa digunakan
bagian lain
│
reference directive
↓
TypeScript compiler
│
outFile
↓
bundle.js
↓
HTML
↓
Browser
Dan kalimat paling penting dari lecture ini adalah:
Kita boleh memecah source code TypeScript menjadi banyak file agar mudah dikelola, tetapi dengan namespace +
outFile, hasil compile-nya bisa digabung menjadi satu file JavaScript.
Satu hal lagi yang perlu kamu pegang untuk lecture-lecture berikutnya: namespace adalah pendekatan lama/khusus TypeScript, sedangkan import/export ES6 modules adalah pendekatan modern. Jadi jangan kaget kalau nanti syntax-nya berubah cukup drastis.