Salin dan Bagikan
Cara Belajar TypeScript untuk JavaScript Developer
TypeScript adalah superset JavaScript yang menambahkan static typing. Mari pelajari cara menggunakannya.
Apa itu TypeScript?
Keuntungan TypeScript
- Type safety (catch errors early)
- Better IDE support (autocomplete)
- Self-documenting code
- Refactoring lebih aman
- Better tooling
- Growing adoption
TypeScript vs JavaScript
// JavaScript
function add(a, b) {
return a + b;
}
add("1", 2); // "12" (string concatenation)
// TypeScript
function add(a: number, b: number): number {
return a + b;
}
add("1", 2); // Error: Argument of type 'string' not assignable
Setup
Install TypeScript
# Global installation
npm install -g typescript
# Project installation
npm init -y
npm install typescript --save-dev
# Initialize tsconfig
npx tsc --init
tsconfig.json
{
"compilerOptions": {
"target": "ES2020",
"module": "commonjs",
"lib": ["ES2020"],
"outDir": "./dist",
"rootDir": "./src",
"strict": true,
"esModuleInterop": true,
"skipLibCheck": true,
"forceConsistentCasingInFileNames": true,
"resolveJsonModule": true,
"declaration": true,
"declarationMap": true,
"sourceMap": true
},
"include": ["src/**/*"],
"exclude": ["node_modules", "dist"]
}
Compile dan Run
# Compile
npx tsc
# Watch mode
npx tsc --watch
# Run with ts-node
npm install -g ts-node
ts-node src/index.ts
Basic Types
Primitive Types
// String
let nama: string = "Budi";
// Number
let umur: number = 25;
let harga: number = 99.99;
// Boolean
let aktif: boolean = true;
// Any (avoid if possible)
let data: any = "could be anything";
// Unknown (safer than any)
let input: unknown = "something";
// Void (function returns nothing)
function log(message: string): void {
console.log(message);
}
// Null dan Undefined
let nullable: null = null;
let undef: undefined = undefined;
Arrays
// Array of numbers
let numbers: number[] = [1, 2, 3];
// Alternative syntax
let strings: Array<string> = ["a", "b", "c"];
// Mixed array with tuple
let tuple: [string, number] = ["Budi", 25];
// Array of objects
let users: { name: string; age: number }[] = [
{ name: "Budi", age: 25 },
{ name: "Ani", age: 23 },
];
Objects
// Inline type
let user: { name: string; age: number } = {
name: "Budi",
age: 25,
};
// Optional property
let config: { host: string; port?: number } = {
host: "localhost",
};
// Readonly
let point: { readonly x: number; readonly y: number } = {
x: 10,
y: 20,
};
// point.x = 5; // Error: Cannot assign to 'x'
Type Aliases dan Interfaces
Type Alias
// Basic type alias
type ID = string | number;
// Object type alias
type User = {
id: ID;
name: string;
email: string;
age?: number;
};
// Union type
type Status = "pending" | "approved" | "rejected";
// Function type
type MathFunc = (a: number, b: number) => number;
const add: MathFunc = (a, b) => a + b;
Interface
interface User {
id: number;
name: string;
email: string;
}
// Extend interface
interface Admin extends User {
role: string;
permissions: string[];
}
// Implement interface
class AdminUser implements Admin {
id: number;
name: string;
email: string;
role: string;
permissions: string[];
constructor(data: Admin) {
this.id = data.id;
this.name = data.name;
this.email = data.email;
this.role = data.role;
this.permissions = data.permissions;
}
}
Type vs Interface
// Interface: can be extended/merged
interface User {
name: string;
}
interface User {
age: number;
}
// User now has both name and age
// Type: can use union/intersection
type StringOrNumber = string | number;
type Combined = User & { email: string };
// Recommendation:
// - Use interface untuk objects
// - Use type untuk unions, primitives, tuples
Functions
Function Types
// Parameter dan return types
function greet(name: string): string {
return `Hello, ${name}!`;
}
// Arrow function
const add = (a: number, b: number): number => a + b;
// Optional parameters
function createUser(name: string, age?: number): User {
return { name, age: age || 0 };
}
// Default parameters
function greet(name: string = "World"): string {
return `Hello, ${name}!`;
}
// Rest parameters
function sum(...numbers: number[]): number {
return numbers.reduce((a, b) => a + b, 0);
}
Function Overloading
function format(value: string): string;
function format(value: number): string;
function format(value: string | number): string {
if (typeof value === "string") {
return value.toUpperCase();
}
return value.toFixed(2);
}
console.log(format("hello")); // "HELLO"
console.log(format(3.14159)); // "3.14"
Generics
Basic Generics
// Generic function
function identity<T>(arg: T): T {
return arg;
}
const str = identity<string>("hello");
const num = identity<number>(42);
const inferred = identity("hello"); // Type inferred
// Generic array
function firstElement<T>(arr: T[]): T | undefined {
return arr[0];
}
Generic Interfaces
interface ApiResponse<T> {
data: T;
status: number;
message: string;
}
interface User {
id: number;
name: string;
}
const userResponse: ApiResponse<User> = {
data: { id: 1, name: "Budi" },
status: 200,
message: "Success",
};
Generic Constraints
interface HasLength {
length: number;
}
function logLength<T extends HasLength>(arg: T): number {
console.log(arg.length);
return arg.length;
}
logLength("hello"); // 5
logLength([1, 2, 3]); // 3
// logLength(123); // Error: number doesn't have length
Utility Types
Built-in Utility Types
interface User {
id: number;
name: string;
email: string;
password: string;
}
// Partial - all properties optional
type PartialUser = Partial<User>;
// Required - all properties required
type RequiredUser = Required<PartialUser>;
// Pick - select properties
type UserPreview = Pick<User, "id" | "name">;
// Omit - exclude properties
type UserWithoutPassword = Omit<User, "password">;
// Readonly - all properties readonly
type ReadonlyUser = Readonly<User>;
// Record - create object type
type UserRoles = Record<string, string[]>;
const roles: UserRoles = {
admin: ["read", "write", "delete"],
user: ["read"],
};
Conditional Types
type IsString<T> = T extends string ? "yes" : "no";
type A = IsString<string>; // "yes"
type B = IsString<number>; // "no"
// Extract dan Exclude
type T1 = Extract<"a" | "b" | "c", "a" | "f">; // "a"
type T2 = Exclude<"a" | "b" | "c", "a">; // "b" | "c"
Classes
Class with Types
class User {
// Properties
public id: number;
public name: string;
private password: string;
protected email: string;
readonly createdAt: Date;
constructor(id: number, name: string, password: string) {
this.id = id;
this.name = name;
this.password = password;
this.email = "";
this.createdAt = new Date();
}
// Method
greet(): string {
return `Hello, ${this.name}!`;
}
// Getter
get displayName(): string {
return this.name.toUpperCase();
}
// Setter
set displayName(value: string) {
this.name = value;
}
}
Abstract Classes
abstract class Animal {
constructor(public name: string) {}
abstract makeSound(): string;
move(): void {
console.log(`${this.name} is moving`);
}
}
class Dog extends Animal {
makeSound(): string {
return "Woof!";
}
}
Type Guards
Type Narrowing
function printValue(value: string | number) {
if (typeof value === "string") {
console.log(value.toUpperCase()); // TypeScript knows it's string
} else {
console.log(value.toFixed(2)); // TypeScript knows it's number
}
}
// instanceof
class Dog {
bark() {
console.log("Woof!");
}
}
class Cat {
meow() {
console.log("Meow!");
}
}
function makeSound(animal: Dog | Cat) {
if (animal instanceof Dog) {
animal.bark();
} else {
animal.meow();
}
}
// Custom type guard
interface Fish {
swim(): void;
}
interface Bird {
fly(): void;
}
function isFish(pet: Fish | Bird): pet is Fish {
return (pet as Fish).swim !== undefined;
}
Modules
Export dan Import
// user.ts
export interface User {
id: number;
name: string;
}
export function createUser(name: string): User {
return { id: Date.now(), name };
}
export default class UserService {
// ...
}
// main.ts
import UserService, { User, createUser } from "./user";
const user: User = createUser("Budi");
Type-only Imports
import type { User } from "./user";
import { type User, createUser } from "./user";
Error Handling
Typed Errors
class AppError extends Error {
constructor(message: string, public code: string, public statusCode: number) {
super(message);
this.name = "AppError";
}
}
function fetchUser(id: number): User {
if (id < 0) {
throw new AppError("Invalid ID", "INVALID_ID", 400);
}
// ...
}
try {
fetchUser(-1);
} catch (error) {
if (error instanceof AppError) {
console.log(error.code, error.statusCode);
}
}
Best Practices
Do’s
// Use strict mode
"strict": true
// Prefer interfaces for objects
interface User { ... }
// Use const assertions
const colors = ["red", "green", "blue"] as const;
// Use unknown instead of any
function parse(input: unknown) { ... }
// Explicit return types for public APIs
export function getUser(id: number): User { ... }
Don’ts
// Avoid any
let data: any; // ❌
// Avoid type assertions when possible
const user = data as User; // ❌ if avoidable
// Avoid non-null assertions
user!.name; // ❌ prefer optional chaining
// Don't ignore errors
// @ts-ignore // ❌
Kesimpulan
TypeScript meningkatkan developer experience dengan type safety dan better tooling. Start dengan basics, gradually add more advanced types seiring kebutuhan.
Artikel Terkait
Link Postingan : https://www.tirinfo.com/cara-belajar-typescript-javascript/
Editor : Hendra WIjaya
Publisher :
Tirinfo
Read : 6 minutes.
Update : 7 January 2026