myHotTake

Tag: TypeScript best practices

  • How Can I Avoid Overusing any in TypeScript?

    If you find this story helpful, feel free to like or share it with others who might be interested!


    I’m running a pet hotel. It’s a place where dogs, cats, birds, and even the occasional iguana come to stay while their owners are away. Now, in this pet hotel, there’s a room called “The Any Room.” It’s a place where any animal can go, no questions asked. Sounds convenient, right? But here’s the catch: because it’s open to all, I never really know what kind of animal might show up there, and it makes it incredibly hard to cater to their specific needs.

    One day, a dog, a cat, and an iguana all check into The Any Room. The dog needs a walk, the cat needs a quiet corner, and the iguana requires a heat lamp. But because they’re all mixed up in The Any Room, I can’t easily provide what each one needs without some confusion. I find myself constantly running back and forth, trying to figure out what belongs to whom. It’s chaos!

    So, I decide to make a change. I start creating specific rooms for each type of animal. Now, there’s a “Dog Room” with plenty of toys and space to run, a “Cat Room” with cozy nooks and scratching posts, and an “Iguana Room” complete with the perfect heat lamp. By organizing my pet hotel this way, I can cater to each animal’s unique needs without the headache.

    In the world of TypeScript, overusing the any type is like relying too much on The Any Room. It might seem convenient at first, but it leads to confusion and errors because I can’t anticipate the specific needs or behaviors of the data. By using more specific types, much like my organized pet rooms, I ensure that my code is clear, predictable, and maintainable. This way, each piece of data gets exactly what it needs, just like the happy animals in my newly organized pet hotel.


    Continuing with my pet hotel, imagine I’ve decided to track the animals in a computer system. Initially, I might be tempted to use the any type for each animal, just like The Any Room, to keep things simple:

    let animal: any;
    
    animal = { type: 'dog', name: 'Buddy', needsWalk: true };
    animal = { type: 'cat', name: 'Whiskers', likesToClimb: true };
    animal = { type: 'iguana', name: 'Iggy', requiresHeatLamp: true };

    This allows me to store any animal, but it doesn’t provide me with information or safety about what properties each animal should have. When I try to access a property like needsWalk, I have no guarantee it exists on the current animal:

    if (animal.needsWalk) {
      console.log(`${animal.name} needs a walk.`);
    }

    This could lead to runtime errors if animal is, say, a cat or an iguana.

    To address this, I start to define more specific types, much like creating separate rooms in the hotel:

    type Dog = {
      type: 'dog';
      name: string;
      needsWalk: boolean;
    };
    
    type Cat = {
      type: 'cat';
      name: string;
      likesToClimb: boolean;
    };
    
    type Iguana = {
      type: 'iguana';
      name: string;
      requiresHeatLamp: boolean;
    };
    
    let specificAnimal: Dog | Cat | Iguana;
    
    specificAnimal = { type: 'dog', name: 'Buddy', needsWalk: true };
    // Now TypeScript knows exactly what properties are available
    
    if (specificAnimal.type === 'dog' && specificAnimal.needsWalk) {
      console.log(`${specificAnimal.name} needs a walk.`);
    }

    By using these specific types, I make sure that I only access properties that are relevant to the type of animal I’m dealing with. This prevents errors and makes my code more predictable and easier to maintain.


    Key Takeaways:

    • Avoid Overuse of any: Just like the confusing Any Room in my pet hotel, using any can lead to unexpected errors and complications in your code. It sacrifices type safety and predictability.
    • Use Specific Types: Define specific types for different data entities in your application. This helps ensure type safety and makes your code more maintainable and understandable.
    • Type Safety: Leveraging TypeScript’s static type checking prevents many common runtime errors and improves the reliability of your code.
  • How to Eliminate Unnecessary any in TypeScript Code?

    If you enjoy this story, feel free to like or share it!


    I am the captain of a ship, setting sail on a long voyage. My ship, once filled with a diverse crew, has just undergone a major upgrade. We’ve replaced some old sails and ropes with new, more efficient ones. However, as we set sail, I notice that some of my crew members are acting like “any” sailors—they’re not specialized and can be doing anything, which makes it hard to know if they’re truly needed or if they’re doing their jobs correctly.

    I start by gathering the crew on deck. I need to identify these “any” sailors who are not performing specific roles. I ask each crew member to tell me their specific duties. If someone says they are just “any” sailor, I dig deeper. I need to understand where they fit in this ship’s journey. Are they really needed on the crow’s nest, manning the sails, or steering the ship? Or are they just drifting from task to task without adding real value?

    Once I identify these “any” sailors, I begin retraining them. I give them specific roles and responsibilities, such as a navigator, a quartermaster, or a helmsman. This way, each person has a clear purpose, and my ship sails more smoothly and efficiently. Now, everyone knows what they are supposed to do, and I can trust that each task is handled by an expert.

    As we continue our voyage, I regularly check in with my crew. I ensure that no one slips back into being an “any” sailor. By doing so, my ship becomes a well-oiled machine, ready to face any storm or challenge that the sea might throw our way. If you found this analogy helpful, feel free to like or share!


    Here’s an example of what I might find:

    let cargo: any = "gold";
    cargo = 100; // Initially a string, now a number
    
    function processCargo(cargo: any): void {
      console.log("Processing", cargo);
    }
    
    processCargo(cargo);

    In this code, the use of any means I could be passing anything into processCargo, and it could lead to unexpected results. Just like my crew needed specific roles, my variables need specific types to ensure everything functions smoothly.

    To fix this, I start by examining each any usage. I question its purpose and try to replace it with a more specific type. Here’s how I might refactor the code:

    let cargo: string = "gold";
    // cargo = 100; // This would now cause a type error
    
    function processCargo(cargo: string): void {
      console.log("Processing", cargo);
    }
    
    processCargo(cargo);

    Now, I’ve assigned a specific type to cargo, ensuring consistency and preventing type-related errors. If I need to handle multiple types, I might use union types or create a more structured approach:

    type Cargo = string | number;
    
    let cargo: Cargo = "gold";
    cargo = 100;
    
    function processCargo(cargo: Cargo): void {
      if (typeof cargo === "string") {
        console.log("Processing string cargo:", cargo);
      } else {
        console.log("Processing numeric cargo:", cargo);
      }
    }
    
    processCargo(cargo);

    Key Takeaways:

    1. Identify and Examine: Just like identifying “any” sailors, scrutinize each any usage to understand its purpose and necessity.
    2. Assign Specific Types: Replace any with more specific types to enhance code readability and reliability.
    3. Use Union Types: If variables can hold multiple types, consider using union types for clarity and flexibility.
    4. Regular Maintenance: Continuously review your code to prevent unnecessary any usages from slipping back in, much like monitoring a crew.