Skip to main content

Command Palette

Search for a command to run...

✨ Mastering TypeScript Fundamentals: Annotations, Inference, any, Function Parameters & void Type

Published
β€’5 min read

Introduction

Whether you're a JavaScript developer dipping your toes into TypeScript or someone refining their TypeScript skills, understanding the core typing system is essential. In this article, we'll deeply explore:

  1. Type Annotations

  2. Type Inference

  3. The any Type

  4. Function Parameters with Annotations

  5. The void Return Type


1️⃣ Type Annotations: Adding a Label to Your Data

Definition: Type annotations explicitly define the type of a variable, parameter, or return value. Think of it as adding a "name tag" to your data that tells TypeScript what kind of value to expect.

πŸ“Œ Why Use Annotations?

  • Catches errors at compile time

  • Improves editor autocompletion

  • Makes code self-documenting

πŸ§ͺ Example 1: Basic Variable Annotations

let name: string = "Alice";
let age: number = 28;
let isLoggedIn: boolean = true;

Here, you're telling TypeScript:

  • name must always be a string

  • age must be a number

  • isLoggedIn must be a boolean

❌ Error Example:

name = 42; // Error: Type 'number' is not assignable to type 'string'

πŸ§ͺ Example 2: Array and Object Annotations

let scores: number[] = [95, 82, 77];  // Array of numbers
let user: { id: number; username: string } = {
  id: 1,
  username: "coder123",
};

πŸ§ͺ Example 3: Union Types

Allow multiple possible types:

let status: string | number;
status = "loading"; // OK
status = 200;       // OK
status = true;      // ❌ Error

2️⃣ Type Inference: When TypeScript Reads Your Mind

Definition: TypeScript can automatically infer the type of a variable if it's initialized with a value.

πŸ§ͺ Example 1: Inferred Types

let language = "TypeScript"; // inferred as string
let version = 5.4;           // inferred as number

This works only when you initialize a variable right away.

πŸ” How It Helps:

language.toUpperCase(); // IntelliSense knows it's a string!
version.toFixed(1);     // Works because it's inferred as number

πŸ§ͺ Example 2: No Initialization

let result; // inferred as `any` (not good)
result = "Success";
result = 100; // No error β€” ⚠️ dangerous!

βœ… Best Practice: Always initialize variables or explicitly annotate them to avoid unintended any usage.


3️⃣ The any Type: The Escape Hatch

Definition: The any type disables type checking β€” it tells TypeScript: β€œI know what I’m doing!”

let mysteryData: any = "Text";
mysteryData = 42;
mysteryData = true;

It behaves like JavaScript β€” flexible, but unsafe.

⚠️ Why You Should Avoid any:

function calculateTax(price: any) {
  return price * 0.1; // πŸ’₯ What if `price` is a string?
}

TypeScript won't complain, but this could crash at runtime.

βœ… Safer Alternative: Use unknown

let input: unknown = "Text";
if (typeof input === "string") {
  console.log(input.toUpperCase());
}

4️⃣ Function Parameters with Annotations

Definition: Functions can have typed parameters and return types to ensure correct usage.

βœ… Syntax:

function functionName(param1: Type, param2: Type): ReturnType {}

πŸ§ͺ Example 1: Typed Parameters and Return

function add(x: number, y: number): number {
  return x + y;
}

If someone tries to call this incorrectly:

add(5, "ten"); // ❌ Error: Argument of type 'string' is not assignable to 'number'

πŸ§ͺ Example 2: Optional Parameters

function greet(name: string, title?: string): string {
  return title ? `Hello, ${title} ${name}` : `Hello, ${name}`;
}

πŸ§ͺ Example 3: Default Parameters

function calculateTotal(price: number, tax: number = 0.05): number {
  return price + price * tax;
}

πŸ§ͺ Example 4: Arrow Functions with Types

const multiply = (a: number, b: number): number => a * b;

5️⃣ The void Type: When Functions Don’t Return Anything

Definition: The void type is used when a function does not return a value.

function logInfo(message: string): void {
  console.log("INFO:", message);
}

βœ… Use Cases:

  • Logging

  • Event handlers

  • Side-effect functions

❌ Invalid Return:

function sayHello(): void {
  return "Hello"; // ❌ Error: Type 'string' is not assignable to type 'void'
}

πŸ§ͺ void in Callbacks

function handleClick(callback: () => void) {
  callback();
}

handleClick(() => {
  console.log("Button clicked!");
});

πŸ“š Bonus Tips

πŸ”„ Type Aliases

You can create custom types using aliases:

type User = {
  id: number;
  name: string;
};

let admin: User = { id: 1, name: "Admin" };

πŸ“ Literal Types

Restrict a value to specific strings or numbers:

let direction: "up" | "down" = "up";
direction = "down"; // βœ…
direction = "left"; // ❌ Error

πŸ“Œ Recap Table

ConceptPurposeExample Syntax
Type AnnotationsDeclare specific typeslet age: number = 25;
Type InferenceTypeScript guesses the typelet name = "John";
any TypeDisable type checkinglet data: any = "hello";
Function TypingAnnotate params & return valuesfunction greet(name: string): string {}
void TypeUsed when function returns nothingfunction log(msg: string): void {}

🧠 Final Thoughts

TypeScript helps you write robust, readable, and maintainable code. By understanding how to use annotations, inference, and function types properly, you’ll prevent bugs before they happen and make your codebase easier to work with.

βœ… Takeaways:

  • Be explicit with types where necessary

  • Leverage inference to reduce boilerplate

  • Avoid any β€” prefer unknown or proper types

  • Type your function signatures

  • Use void for functions that don’t return anything

More from this blog

Ramkumar's blog

14 posts

Hello world! 🌐 I'm Ramkumar, your friendly neighbourhood frontend developer. Passionate about crafting sleek websites that make you go "Whoa, that's rad!" πŸ’». I'm fluent in HTML, CSS, and JavaScript.