Master advanced TypeScript concepts: modules, async/await, and decorators for production-ready applications.
Learn modules & namespaces, async/await patterns, and decorators for real-world TypeScript.
export to make code available to other files:// Named exports
export function add(a: number, b: number): number {
return a + b;
}
export const PI = 3.14159;
export class Calculator {
multiply(a: number, b: number): number {
return a * b;
}
}// Default export (one per file)
export default class MathUtils {
static square(n: number): number {
return n * n;
}
}// Named imports
import { add, PI, Calculator } from './math';
// Default import (any name works)
import MathUtils from './math';
// Import all as namespace
import * as Math from './math';
// Renaming imports
import { add as sum } from './math';namespace Validation {
export interface StringValidator {
isValid(s: string): boolean;
}
export class EmailValidator implements StringValidator {
isValid(s: string): boolean {
return s.includes("@");
}
}
export class PhoneValidator implements StringValidator {
isValid(s: string): boolean {
return /^\d{10}$/.test(s);
}
}
}
// Usage
const emailValidator = new Validation.EmailValidator();
console.log(emailValidator.isValid("test@email.com"));// index.ts (barrel file)
export { add, subtract } from './arithmetic';
export { Calculator } from './calculator';
export * from './constants';add(5, 3) = 8
PI = 3.14159
Calculator: 4 * 7 = 28
MathUtils.square(5) = 25
Email valid: true
Phone valid: true
export function add(a: number, b: number): number { }export class Calculator { }export const PI = 3.14159;namespace Name { export class X { } }new Validation.EmailValidator()Review feedback below
function fetchUser(id: number): Promise<User> {
return new Promise((resolve, reject) => {
setTimeout(() => {
if (id > 0) {
resolve({ id, name: "Alice", email: "alice@test.com" });
} else {
reject(new Error("Invalid ID"));
}
}, 1000);
});
}async function getUser(id: number): Promise<User> {
const user = await fetchUser(id);
return user;
}
// The return type is inferred as Promise<User>async function safeGetUser(id: number): Promise<User | null> {
try {
const user = await fetchUser(id);
return user;
} catch (error) {
console.error("Failed to fetch user:", error);
return null;
}
}async function getAllUsers(ids: number[]): Promise<User[]> {
const promises = ids.map(id => fetchUser(id));
const users = await Promise.all(promises);
return users;
}async function fetchWithTimeout<T>(
promise: Promise<T>,
ms: number
): Promise<T> {
const timeout = new Promise<never>((_, reject) => {
setTimeout(() => reject(new Error("Timeout")), ms);
});
return Promise.race([promise, timeout]);
}async function processSequentially(ids: number[]): Promise<void> {
for (const id of ids) {
const user = await fetchUser(id);
console.log("Processed:", user.name);
}
}Fetching user 1...
User fetched: { id: 1, name: "Alice" }
Parallel fetch complete: 3 users
Sequential processing done
Error handled gracefully
function fn(): Promise<User> { return new Promise(...) }async function fn(): Promise<User> { }const user = await fetchUser(1);try { await fn() } catch (e) { }await Promise.all([p1, p2, p3])Review feedback below
"experimentalDecorators": true in tsconfig.json.function Logger(constructor: Function) {
console.log("Logging class:", constructor.name);
}
@Logger
class Person {
constructor(public name: string) {}
}
// Logs: "Logging class: Person" when class is definedfunction LoggerWithPrefix(prefix: string) {
return function(constructor: Function) {
console.log(prefix + constructor.name);
};
}
@LoggerWithPrefix("CLASS: ")
class Animal { }function Log(
target: any,
propertyKey: string,
descriptor: PropertyDescriptor
) {
const originalMethod = descriptor.value;
descriptor.value = function(...args: any[]) {
console.log("Calling " + propertyKey + " with:", args);
const result = originalMethod.apply(this, args);
console.log("Result:", result);
return result;
};
}
class Calculator {
@Log
add(a: number, b: number): number {
return a + b;
}
}function Required(target: any, propertyKey: string) {
let value: any;
Object.defineProperty(target, propertyKey, {
get() { return value; },
set(newValue) {
if (newValue === undefined || newValue === null) {
throw new Error(propertyKey + " is required");
}
value = newValue;
}
});
}function ValidateParam(
target: any,
propertyKey: string,
parameterIndex: number
) {
console.log("Parameter " + parameterIndex + " of " + propertyKey + " needs validation");
}function Measure(
target: any,
propertyKey: string,
descriptor: PropertyDescriptor
) {
const original = descriptor.value;
descriptor.value = function(...args: any[]) {
const start = performance.now();
const result = original.apply(this, args);
const end = performance.now();
console.log(propertyKey + " took " + (end - start) + "ms");
return result;
};
}Class decorated: Person
Calling add with: [5, 3]
Result: 8
Method took 0.5ms
Property validated
function Dec(constructor: Function) { }function Dec(arg) { return function(constructor) { } }function Dec(target, key, descriptor) { }@Decorator class MyClass { }descriptor.value = function(...args) { original.apply(this, args) }Review feedback below