»

»

Code Review TypeScript: A Practical Guide and Checklist
Index

Code Review TypeScript: A Practical Guide and Checklist

Índice:

Let’s be honest: a lot of code reviews are performative. We check for obvious bugs, suggest a few variable renames, and nitpick code style that a linter should’ve caught. We click “Approve,” collect our team-player points, and move on. For general Best Practices for Code Review in JavaScript, there are other great resources. But a good **TypeScript Code Review** is a totally different beast. It’s less about ticking boxes and more about collaborative architecture.

When you’re reviewing TypeScript, you’re not just looking at code; you’re looking at the *shape* of the data, the *contracts* between components, and the *story* the types are telling. Get it right, and you prevent entire classes of bugs. Get it wrong, and you’re just writing JavaScript with extra steps.

This isn’t about dogma. It’s about making our lives easier, building things that don’t break in weird ways, and leaving the codebase better than we found it.

Beyond “Looks Good to Me”

A great TypeScript review goes deeper than surface-level correctness. It’s a force multiplier for quality, acting as a key part of Improving Code Quality: A Developer’s Guide.

First, it’s our best defense against type-related bugs. Think about that one time a function expected a `string` but got a `number` at runtime because an API response changed. A proper type definition, maybe with a validation library like Zod, would have caught that before it ever hit production.

Second, it drastically improves readability. Good types are a form of documentation that never goes out of date. When you see function processUser(user: User), you immediately know what kind of data structure to expect. No more digging through three files to figure out what a `user` object looks like.

But here’s the part that senior devs really care about: it forces better API design. When you’re reviewing a PR, you’re the first “customer” of that new function, component, or class. If you can’t figure out how to use it from its type signature alone, the API is too complicated. The review becomes a design session.

What to Actually Look For: The Core of a Great TypeScript Code Review

Okay, so where do you focus your attention? When considering What to Prioritize in a Code Review, it comes down to a few key areas.

Type Safety and Correctness

This is the starting point. If the types are wrong, nothing else matters.

This content is solid — clear opinion, technical depth, and great examples. Structure’s already good. Below is a slightly refined version to improve flow, consistency, and rhythm (especially in titles and pacing):

🔓 The any Loophole

My take?
any is a code smell — not a cardinal sin. It basically says:

“I’m giving up on type safety here.”

Every use of any should be questioned:

  • Is it temporary?
  • Did it come from a third-party lib with no types?
  • Could you use unknown instead?

unknown is the safer cousin of any: it forces you to validate the type before using the variable — which is almost always the right thing to do.

🚨 Abusing Type Assertions

Seeing as User or <User> is a red flag.
It’s like telling TypeScript:

“Trust me, I know what I’m doing.”

Sometimes you do — like:

document.getElementById('app') as HTMLDivElement

But most of the time, type assertions are used to cover up a type mismatch that should be fixed properly.

Use type guards instead:

function isUser(obj: unknown): obj is User

It’s more robust, more explicit, and way safer.

✅ Dealing with null and undefined

If your project still doesn’t use "strictNullChecks": true in tsconfig.json, stop what you’re doing and talk to the team about enabling it.

It hurts a bit at first — but it eliminates errors like:
"Cannot read property 'x' of undefined"

In code review, watch out for overly defensive code:

if (user && user.profile && user.profile.name)

When it could just be:

user?.profile?.name

🎯 API Design and Type Definitions

This is where you wear your product designer hat.
How does using this code feel?

Type names that tell a story

ItemData is a lazy name.
What kind of item? ProductListItem? ShoppingCartItem?
Be specific — good names make code self-explanatory.

For functions (especially in shared monorepo packages), explicit return types are a must.
Don’t make the consumer guess what your function returns.

Clean, consistent interfaces

Look at the props of a React component.
Is it just a bunch of booleans?

<Button isPrimary isDestructive isIconOnly />

That’s a classic sign that a union type would be better:

<Button variant="primary" | "destructive" | "icon" />

This prevents impossible states — you don’t want a button to be both “primary” and “destructive”.

Generics for reuse

If you see similar functions that only differ in the types they handle, that’s a perfect use case for generics.

Example:

fetchUserData()
fetchProductData()

Could become:

fetchData<T>(url: string): Promise<T>

Spotting these during a review is a big win for maintainability.

🛑 Error Handling

Errors will happen. How does your type system deal with them?

The key point here is: how do you safely catch them?

Since TypeScript 4.4, the default type in catch blocks is unknown (it used to be any). That’s great for safety — but only if the team uses it correctly.

Problematic pattern (still common in older configs):

try {
  // ...
} catch (err) {
  console.error(err.message); // err is `any`
}

The ideal is always to be explicit and safe:

try {
  // ...
} catch (err: unknown) {
  if (err instanceof Error) {
    console.error(err.message);
  } else {
    console.error("An unknown error occurred");
  }
}

Reviewers should suggest this pattern whenever they see a vague catch.

It ensures you don’t try to access properties on something that might be a string, a number, or even null.

How to Run the Review Process

The process matters as much as the content. While this guide focuses on human interaction, for insights into AI Code Reviews vs. Traditional Code Reviews, you might explore other discussions.

For the Author: Set Yourself Up for Success

Don’t just toss your code over the wall. A bit of prep goes a long way.

Do a self-review first:

Run tsc --noEmit — it’s your first line of defense. It catches type errors without having to build the whole project.

Run your linter and formatter: eslint . --fix and prettier --write .

Fix what’s automatic. That frees up the reviewer to focus on what actually matters.

Want an extra hand? You can also use AI tools to help review your code.

Write a solid PR description: Explain the why, not just the what.

If you had to write a really complex mapped or conditional type, add a comment or link to the TypeScript doc you used. Give the reviewer some context!

For the Reviewer: Be a Mentor, Not a Cop

Your goal is to improve the code — not prove you’re smarter.

Understand the intent: Read the PR description and the linked ticket. What problem is this change solving? That context helps you avoid off-target suggestions.

Prioritize your feedback:
Use prefixes in your comments. Something simple works great:

  • [Blocker]: “This looks like a bug or a significant architecture issue. We need to fix it before merging.”
  • [Suggestion]: “I think this could be clearer/more efficient by doing X. What do you think?”
  • [Nitpick]: “Just a style thing — feel free to ignore.”

Offer solutions: Don’t just say “this is confusing.” Say: “This conditional logic is a bit hard to follow. How about extracting it to a function called isEligibleForDiscount(cart)? It would make the intent clearer.”

TypeScript Code Review Checklist

Here’s a practical, no-fluff checklist to run through on your next PR. Think of it as a guide, not a rigid set of rules.

✅ Typing & Correctness

  • Is any used? If so, is it justified? Could unknown be a safer choice?
  • Are type assertions (as Foo) used? Could a type guard or better type eliminate the need?
  • Are function return types explicit, especially for exported functions?
  • Are generics used where logic is reusable?
  • Are null and undefined handled properly? Is optional chaining (?.) and nullish coalescing (??) used correctly?
  • Are union types (|) used to represent valid states instead of multiple booleans?

✅ Organization & Maintainability

  • Are type names descriptive and meaningful? (Product vs Data)
  • Are types co-located with the code that uses them, or placed in a clearly scoped types.ts?
  • In monorepos, are shared types exported cleanly with clear boundaries?
  • Do complex types have a named type or interface to promote reuse and clarity?

✅ Testing

  • Is complex type logic (e.g., conditional types) tested with tsd, expect-type, or similar tools?
  • Are mocks and test data correctly typed and representative of real data structures?

✅ Security

  • Is external data (API responses, user input) validated before being trusted? Is it typed as unknown initially and narrowed later?
  • Are sensitive strings (e.g., passwords, tokens) branded or typed to prevent accidental logging?
    type Password = string & { __brand: 'password' }
    

✅ Frontend (React)

  • Are component props clearly typed? Are optional props marked with ??
  • Are event handlers correctly typed (e.g., React.MouseEvent<HTMLButtonElement>) instead of any?
  • When using useState, is the initial state typed correctly? If nullable, is it useState<Type | null>(null)?
  • Do custom hooks return a clear, well-typed tuple or object (e.g., [string, (value: string) => void])?

✅ Backend (Node.js)

  • Are API request bodies and query parameters validated and typed (e.g., using Zod, Joi, etc.)?
  • Are database models/schemas strongly typed and reflective of the actual DB schema?
  • Are environment variables parsed and typed at startup, rather than left as string | undefined?

By moving beyond a simple “LGTM” and engaging with the code on this level, you’re doing more than just reviewing code. You’re shaping a more stable, maintainable, and developer-friendly product, contributing to how to build a strong code review culture within your team. And that’s a review worth doing.

Posted by:
Share!

Automate your Code Reviews with Kody

Posts relacionados

Let’s be honest: a lot of code reviews are performative. We check for obvious bugs, suggest a few variable renames, and nitpick code style that a linter should’ve caught. We

Let’s be honest: a lot of code reviews are performative. We check for obvious bugs, suggest a few variable renames, and nitpick code style that a linter should’ve caught. We

Let’s be honest: a lot of code reviews are performative. We check for obvious bugs, suggest a few variable renames, and nitpick code style that a linter should’ve caught. We