CR

April 25, 2025

Typescript Assertions; Trust me bro

Cassius Reynolds
Typescript Assertions; Trust me bro

Using TypeScript in my projects has greatly improved code quality and consistency, especially for production-level code. However, like many developers, it took me a while to fully grasp its core concepts. Initially, my main goal was just making the red squiggly lines disappear. At times, the errors TypeScript threw at me were confusing, especially as my codebase grew. This frustration often led to lengthy debugging sessions, where a type seemed correct everywhere except one spot, causing unnecessary headaches.


One recent lesson will now stick with me forever. Learning through experience is effective because the irritation from a tough bug leaves a lasting impression. It’s almost like a mild form of PTSD—when the problem reoccurs, you instantly remember it and know exactly how to resolve it efficiently. My latest encounter involved understanding the difference between type assertion and generic parameters, particularly in the context of asynchronous API responses.


In my latest project, I integrated the Google Books API with Next.js, Supabase, and Auth.js to sharpen my skills with the Next.js App Router. One feature I was proud of was the advanced search, formatting user-defined filters into queries the Google Books API could process to return precise results. To display books correctly, I needed to ensure the API response matched the `Book` type I defined.


Initially, I wrote my function without worrying about type safety, intending to handle it afterward.


const fetchBooks = async () => {
  const { volumeId } = advancedSearchFormData;
  const isVolumeIDSearch = Boolean(volumeId.value);

  const query = buildAdvancedSearchUrl(advancedSearchFormData);

  try {
    const { data: resp } = await axios.get(
      `/api/books/advanced-search${isVolumeIDSearch ? "/" : "?"}${query}`
    );
    setBooks(resp);
    scrollToSection(advancedSearchResultsRef);
  } catch (err) {
    console.error(err);
    setBooks([]);
  }
};


This was after some refactoring, and I still wanted type enforcement. That's when I stumbled onto the critical difference between type assertion and generic parameters.


When you use type assertion:


const { data: resp }: Book[] = await axios.get(url);


You're essentially telling TypeScript, "Trust me, bro. This data is definitely shaped like this." TypeScript takes your word for it, offering no compile-time protection. If you're mistaken, your error surfaces at runtime—which is exactly what we're trying to avoid.

So if "trust me, bro" isn't enough, what should you do?


I frequently saw generic parameters like:

fn<T>(args)

I've see these before function calls but never truly understood why. I used them routinely with hooks like useState

const [count, setCount] = useState<number>(0);


However, the key difference here is that generic parameters explicitly instruct TypeScript to expect a certain type, allowing it to verify and enforce that expectation. If there's a mismatch, TypeScript throws a compile-time error immediately, preventing potential runtime issues.


Applying this to my API response was crucial. My `useState` hook expected a type of `Book[]`. To ensure that the API response truly matched this type, I needed TypeScript’s verification, not just blind trust.


Here's the corrected approach using generic parameters:

const { data: resp } = await axios.get<Book[]>(url);


This method ensures compile-time safety because TypeScript verifies the response shape, rather than blindly trusting it.


Ultimately, the key lesson is this:


Type Assertion

  • You're asking TypeScript to "trust me, bro." It’s suitable for scenarios where data shapes are static and certain.

Generic Parameters

  • You're allowing TypeScript to verify and enforce type safety, ideal for dynamic scenarios like API responses.


Whenever possible, prefer generic parameters to leverage TypeScript’s full capability to prevent bugs and maintain high-quality code.


And remember, sometimes "trust me, bro" just isn't enough.