{
  "$type": "site.standard.document",
  "bskyPostRef": {
    "cid": "bafyreib3hwo3jecgkrmdl4u4q6n3pt4anrqfkq3qyerq4gy4vq6x76u5gy",
    "uri": "at://did:plc:25rdn5elo5izoxrmtis34zuk/app.bsky.feed.post/3momgat4srgz2"
  },
  "coverImage": {
    "$type": "blob",
    "ref": {
      "$link": "bafkreiccp2gft2kyrqm2235pqsp423kq7dej6rkftl2fe5dy5vlpmzrvme"
    },
    "mimeType": "image/webp",
    "size": 71578
  },
  "path": "/ramesh_s_a8f0867d239e927c/typescript-types-demystified-simple-types-special-types-and-type-inference-5bf0",
  "publishedAt": "2026-06-19T03:22:28.000Z",
  "site": "https://dev.to",
  "tags": [
    "beginners",
    "javascript",
    "tutorial",
    "typescript",
    "post"
  ],
  "textContent": "#  TypeScript Types Demystified: Simple Types, Special Types, and Type Inference\n\n_In the first post, we covered why TypeScript exists and how to write your first program. Now it's time to get comfortable with the type system itself — the foundation everything else is built on._\n\nBy the end of this post, you'll know how to type variables, arrays, and function parameters correctly. You'll also understand the \"special\" types that trip up most beginners: `any`, `unknown`, `never`, and `void`.\n\n##  The Core Primitive Types\n\nTypeScript's basic types map directly to JavaScript's primitives:\n\n\n\n    // string\n    let firstName: string = \"Ramesh\";\n    let greeting: string = `Hello, ${firstName}`;\n\n    // number (no separate int/float — it's all number)\n    let age: number = 31;\n    let price: number = 9.99;\n    let hex: number = 0xFF;\n\n    // boolean\n    let isLoggedIn: boolean = true;\n    let hasAccess: boolean = false;\n\n\nThese are the types you'll use most often. Simple, predictable, and exactly what you'd expect.\n\n##  Type Inference: TypeScript Does the Work\n\nYou don't always have to write the type. TypeScript **infers** it from the value you assign:\n\n\n\n    let city = \"Chennai\";    // TypeScript infers: string\n    let year = 2026;         // TypeScript infers: number\n    let isActive = true;     // TypeScript infers: boolean\n\n\nOnce inferred, that type is locked in:\n\n\n\n    let city = \"Chennai\";\n    city = 42; // ❌ Error: Type 'number' is not assignable to type 'string'\n\n\n**Rule of thumb:** Let TypeScript infer types for local variables. Write explicit annotations for function parameters and return types.\n\n\n\n    // Let inference work for variables\n    const scores = [95, 87, 72]; // inferred as number[]\n\n    // Be explicit for function signatures\n    function calculateAverage(scores: number[]): number {\n      return scores.reduce((a, b) => a + b, 0) / scores.length;\n    }\n\n\n##  Explicit vs Inferred — When to Choose Each\n\n\n    // ✅ Explicit annotation — good for function params & return types\n    function formatName(first: string, last: string): string {\n      return `${first} ${last}`;\n    }\n\n    // ✅ Inferred — good for simple variable assignments\n    const result = formatName(\"Ramesh\", \"Kumar\"); // inferred as string\n\n    // ❌ Over-annotating — redundant when value makes it obvious\n    const count: number = 5; // The `= 5` already tells TypeScript it's a number\n\n\n##  Arrays and Tuples\n\n**Arrays** hold multiple values of the same type:\n\n\n\n    // Two equivalent syntaxes\n    let tags: string[] = [\"typescript\", \"javascript\", \"react\"];\n    let scores: Array<number> = [95, 87, 72];\n\n    // TypeScript will catch wrong types in arrays\n    tags.push(42); // ❌ Error: Argument of type 'number' is not assignable to type 'string'\n\n\n**Tuples** are fixed-length arrays where each position has a specific type:\n\n\n\n    // A tuple: exactly [string, number]\n    let user: [string, number] = [\"Ramesh\", 31];\n\n    // Order and types are both enforced\n    let wrongOrder: [string, number] = [31, \"Ramesh\"]; // ❌ Error\n\n    // Accessing tuple elements\n    console.log(user[0]); // \"Ramesh\" — TypeScript knows this is string\n    console.log(user[1]); // 31 — TypeScript knows this is number\n\n\nTuples are great for things like coordinate pairs, key-value pairs, or when returning multiple values from a function:\n\n\n\n    function getMinMax(numbers: number[]): [number, number] {\n      return [Math.min(...numbers), Math.max(...numbers)];\n    }\n\n    const [min, max] = getMinMax([3, 1, 7, 2, 9]);\n    // min: number, max: number — fully typed!\n\n\n##  Union Types: When a Value Can Be Multiple Types\n\nSometimes a value can legitimately be more than one type. That's what union types handle:\n\n\n\n    // This function accepts string OR number\n    function formatId(id: string | number): string {\n      return `ID-${id}`;\n    }\n\n    formatId(\"abc123\"); // ✅\n    formatId(42);       // ✅\n    formatId(true);     // ❌ Error: boolean not in the union\n\n\nUnion types are especially useful for API responses, form inputs, and optional values:\n\n\n\n    // A status that can only be one of these three strings\n    let orderStatus: \"pending\" | \"shipped\" | \"delivered\";\n\n    orderStatus = \"shipped\";   // ✅\n    orderStatus = \"cancelled\"; // ❌ Error: not in the union\n\n    // A value that might not exist yet\n    let userId: number | null = null;\n    userId = 101; // Fine, it's assigned now\n\n\n##  Special Types: `any`, `unknown`, `never`, `void`\n\nThese four confuse most beginners. Here's each one explained clearly.\n\n###  `any` — The Escape Hatch (Use Sparingly)\n\n`any` turns off TypeScript's type checking for that value:\n\n\n\n    let data: any = \"hello\";\n    data = 42;        // Fine\n    data = true;      // Fine\n    data.foo.bar();   // Fine — no error, even if this blows up at runtime!\n\n\nWhen to use it: Almost never. `any` defeats the purpose of TypeScript. It's there as a last resort when migrating old JavaScript code.\n\n\n\n    // ❌ Overusing any — you've lost all type safety\n    function processData(input: any): any { ... }\n\n    // ✅ Be specific whenever possible\n    function processData(input: string[]): number { ... }\n\n\n###  `unknown` — The Safe Version of `any`\n\n`unknown` says \"this could be anything, but I need to check before I use it\":\n\n\n\n    let userInput: unknown = getUserInput();\n\n    // ❌ Can't use unknown directly\n    console.log(userInput.toUpperCase()); // Error!\n\n    // ✅ Must narrow the type first\n    if (typeof userInput === \"string\") {\n      console.log(userInput.toUpperCase()); // Now it's safe\n    }\n\n\n**Prefer`unknown` over `any`** when you genuinely don't know the type. It forces you to handle the uncertainty explicitly.\n\n###  `void` — Functions That Return Nothing\n\nUse `void` when a function doesn't return a value:\n\n\n\n    function logMessage(message: string): void {\n      console.log(message);\n      // No return statement needed\n    }\n\n    // Trying to use the return value of a void function makes no sense\n    const result = logMessage(\"hello\"); // result is void — useless\n\n\n###  `never` — Code That Never Completes\n\n`never` represents values that never occur. It's used for:\n\n  1. Functions that always throw an error\n  2. Functions with infinite loops\n  3. Exhaustive type checking\n\n\n\n\n    // Always throws — never returns\n    function throwError(message: string): never {\n      throw new Error(message);\n    }\n\n    // Exhaustive check — if you add a new status and forget to handle it,\n    // TypeScript will error here\n    function handleStatus(status: \"active\" | \"inactive\"): string {\n      if (status === \"active\") return \"User is active\";\n      if (status === \"inactive\") return \"User is inactive\";\n\n      // This line should be unreachable\n      const _exhaustive: never = status; // ❌ Error if you missed a case\n      return _exhaustive;\n    }\n\n\n`never` is an advanced concept — don't worry if it doesn't fully click yet. You'll encounter it naturally as you write more TypeScript.\n\n##  Quick Reference: All the Types We Covered\n\n\n    // Primitives\n    let name: string = \"Ramesh\";\n    let age: number = 31;\n    let active: boolean = true;\n\n    // Arrays\n    let tags: string[] = [\"ts\", \"js\"];\n    let ids: number[] = [1, 2, 3];\n\n    // Tuples\n    let point: [number, number] = [10, 20];\n\n    // Union\n    let id: string | number = \"abc\";\n    let status: \"on\" | \"off\" = \"on\";\n\n    // Special types\n    let anything: any = \"...\";     // Avoid when possible\n    let safeAny: unknown = \"...\";  // Safer — must narrow before use\n    function log(): void { ... }   // No return value\n    function fail(): never { throw new Error(); } // Never returns\n\n\n##  Wrapping Up\n\nThe TypeScript type system is deep, but the everyday usage is straightforward. Here's what to take away:\n\n  * **Primitives** — `string`, `number`, `boolean` cover most cases\n  * **Type inference** — TypeScript is smart; you don't need to annotate everything\n  * **Arrays** — `string[]` or `Array<string>`, your choice\n  * **Tuples** — fixed-length, fixed-type arrays\n  * **Union types** — when a value can be more than one type\n  * **`any`** — avoid it; **`unknown`** — use this instead when you must\n  * **`void`** — functions with no return; **`never`** — functions that never return normally\n\n\n\nFound this helpful? Follow for the rest of the series. Questions or corrections? Drop them in the comments.",
  "title": "TypeScript Types Demystified: Simple Types, Special Types, and Type Inference"
}