S SmartDocs
Chuỗi bài: Typescript typescript 144 dòng · Cập nhật 2025-12-27

09-type-assertions.ts

Typescript/src/01-beginner/09-type-assertions.ts

// ============================================
// 09. Type Assertions
// ============================================

console.log("=== TYPE ASSERTIONS IN TYPESCRIPT ===\n");

// as Syntax (Preferred)
console.log("=== 'as' SYNTAX (PREFERRED) ===\n");

let value: any = "hello world";
let strLength: number = (value as string).length;

console.log(`value: any = "${value}"`);
console.log(`(value as string).length = ${strLength}`);
console.log("  The 'as' keyword tells TypeScript to treat value as a specific type");

// Type Assertions vs Type Guards
console.log("\n=== TYPE ASSERTIONS VS TYPE GUARDS ===\n");

// Type Assertion (You tell TypeScript)
let value2: any = "hello";
let str = value2 as string; // You're asserting, but no runtime check
console.log("Type Assertion (you tell TypeScript):");
console.log(`  value2: any = "${value2}"`);
console.log(`  str = value2 as string → "${str}"`);
console.log("  ⚠️  No runtime check - you're responsible for correctness");

// Type Guard (TypeScript checks)
function isString(value: any): value is string {
  return typeof value === "string";
}

let value3: any = "hello";
console.log("\nType Guard (TypeScript checks):");
console.log(`  value3: any = "${value3}"`);
if (isString(value3)) {
  // TypeScript knows it's string here
  const upper = value3.toUpperCase();
  console.log(`  After type guard check: ${upper}`);
  console.log("  ✅ TypeScript knows it's a string here");
}

// Double Assertions
console.log("\n=== DOUBLE ASSERTIONS ===\n");

let value4: string = "hello";
console.log(`value4: string = "${value4}"`);
console.log("Double assertion through 'any':");
// Sometimes you need to assert through 'any' first
// let num = value4 as any as number; // Use sparingly
console.log("  // value4 as any as number - Use sparingly!");
console.log("  ⚠️  This bypasses type safety - only use when absolutely necessary");

// Non-null Assertion Operator
console.log("\n=== NON-NULL ASSERTION OPERATOR ===\n");

// Note: DOM types are for browser environments
// In Node.js, we'll use a mock example instead
function getElement(id: string): string | null {
  // In a real browser environment, this would be:
  // return document.getElementById(id);
  // For Node.js demo, we'll return a mock value
  return id ? `element-${id}` : null;
}

console.log("Non-null assertion operator (!):");
const element = getElement("myDiv")!; // Non-null assertion
console.log(`  getElement("myDiv")! = "${element}"`);
console.log("  The '!' operator tells TypeScript we're certain it's not null");
console.log("  ⚠️  Use only when you're absolutely sure it won't be null");

// Equivalent to:
const element2 = getElement("myDiv") as string;
console.log(`\n  Equivalent: getElement("myDiv") as string = "${element2}"`);

// Common Use Cases
console.log("\n=== COMMON USE CASES ===\n");

// DOM Manipulation (Node.js compatible example)
console.log("1. Type Assertion for Element Types:");
function getInputElement(id: string): string {
  // In browser: return document.getElementById(id) as HTMLInputElement;
  // For Node.js compatible example:
  return `input-element-${id}` as string;
}

const input = getInputElement("username");
console.log(`  getInputElement("username") = "${input}"`);
console.log("  In browser: Asserts element is HTMLInputElement, not just HTMLElement");

// Working with any
console.log("\n2. Working with 'any' type:");
function getDataFromAPI(): any {
  return { name: "Alice", age: 25 };
}

let data: any = getDataFromAPI();
let user = data as { name: string; age: number };
console.log(`  data from API:`, data);
console.log(`  user = data as { name: string; age: number }`);
console.log(`  user.name = "${user.name}"`);
console.log("  ✅ Now TypeScript knows the structure of user");

// Narrowing Union Types
console.log("\n3. Narrowing Union Types:");
function processValue(value: string | number) {
  if (typeof value === "string") {
    // TypeScript knows it's string here
    const upper = value.toUpperCase();
    console.log(`  processValue("hello") → "${upper}"`);
  } else {
    // TypeScript knows it's number here
    const fixed = value.toFixed(2);
    console.log(`  processValue(42) → "${fixed}"`);
  }
}

processValue("hello");
processValue(42);

// Example: Safe type assertion
console.log("\n4. Safe Type Assertion (Best Practice):");
interface User {
  name: string;
  age: number;
}

function processUser(data: unknown): User {
  // Validate first, then assert
  if (typeof data === "object" && data !== null && "name" in data && "age" in data) {
    return data as User;
  }
  throw new Error("Invalid user data");
}

const validData = { name: "Alice", age: 25 };
const processedUser = processUser(validData);
console.log(`  processUser({ name: "Alice", age: 25 }) →`, processedUser);
console.log("  ✅ Always validate before asserting!");

console.log("\n=== DEMO COMPLETE ===");

export { strLength, isString, processValue, processUser };

Bài viết liên quan