27.7 Event Types: React.MouseEvent, React.ChangeEvent, and More

Alright, let’s talk about events. You’ve handled events in vanilla JavaScript: a simple onclick here, an onchange there. It’s a straightforward, if slightly clunky, affair. Then you waltz into the React ballroom, and suddenly you’re expected to dance with React.MouseEvent<HTMLButtonElement>. It feels like your plain old Event object got a fancy, overly verbose makeover. Why the ceremony? It boils down to one beautiful, non-negotiable TypeScript truth: type safety. React wraps the browser’s native event object into its own synthetic event system for performance and consistency. Our job is to tell TypeScript exactly what kind of event we’re handling and, crucially, which HTML element is producing it. This stops you from trying to get .value from a <div> (which would be embarrassing) or .checked from a <select> (which is just nonsense). We’re not just preventing runtime errors; we’re designing our component contracts to be unbreakable.

27.6 Discriminated Union Props for Polymorphic Components

Right, so you’ve built a few components. A Button, a Card. You pass some strings, maybe a boolean for disabled. It feels good. Then the product manager waltzes in and says, “Great, but now we need a component that can either be a primary button, a secondary button, or a hyperlink that looks like a button. Oh, and if it’s a link, it needs an href and a target, but if it’s a button, it needs an onClick and a type.”

27.5 Generic Components: Reusable Components with Type Parameters

Right, so you’ve built a few <Button> and <Card> components. They work. They’re type-safe. You feel good. Then your PM walks over and says, “Great, now can we have a <Select> where the options can be strings, numbers, or maybe even entire user objects? And a <DataTable> that can take any sort of row shape? And, oh, a function that can log any value but also return it?” This is where you graduate from just using TypeScript to wielding it. You need generic components. The concept is simple: it’s a component that defers specifying its exact data types until you use it. Think of it like a function argument, but for types. You’re making a promise: “I will work with whatever type you give me later, and I’ll make sure you use it correctly.”

27.4 Children Prop: React.ReactNode, React.ReactElement, and PropsWithChildren

Alright, let’s talk about the children prop. You’ve seen it. You’ve used it. You’ve probably typed it as any or just ignored it entirely to make the red squiggly line in your editor go away. We’ve all been there, but it’s time to level up. In React, children is a special prop, passed implicitly. It’s the content you put between your component’s opening and closing tags. Think of <Button>Click Me!</Button> – "Click Me!" is the children prop. Simple, right? The complexity comes when you, the brilliant developer, want to type this in TypeScript. What the heck goes in that interface?

27.3 Typing Props: Required, Optional, and Defaults with Destructuring

Right, let’s talk about props. They’re the lifeblood of your components, the parameters of your UI functions. And in TypeScript, we get to move from the wild west of “I hope this object has the right stuff” to the rigorously patrolled border of “I will not let you pass without the correct paperwork.” The core concept is the interface (or a type alias, but I prefer interface for objects—it feels more intentional). This is where you define the contract for your component.

27.2 Typing Functional Components: React.FC vs Direct Return Types

Alright, let’s settle a holy war, shall we? When you define a functional component in TypeScript, you’re immediately faced with a choice: do you slap a React.FC type on it, or do you just type the props and let the return type be inferred? This seems like a trivial stylistic decision, but it comes with real-world consequences that range from “mildly annoying” to “genuinely problematic.” Let’s break it down. The Case for React.FC The React.FC (or its longer alias, React.FunctionComponent) approach is the old guard. It was the officially recommended way for a long time, and you’ll see it in a ton of legacy code. Here’s what it looks like:

27.1 JSX and TSX: The jsx Compiler Option

Right, let’s talk about the jsx compiler option. This is one of those things you set once in your tsconfig.json and then blissfully forget about until your editor starts screaming at you for a reason you don’t understand. It’s not magic, but it is the secret sauce that makes your <div /> turn into something JavaScript can actually run. The core job of this option is to tell the TypeScript compiler, “Hey, you’re about to see some XML-like syntax that isn’t valid JavaScript. I need you to do one of two things: 1) transform it into regular JavaScript function calls for me, or 2) just leave it alone and let something else (like Babel) handle it.” This decision is crucial because it dictates your entire build pipeline.

— joke —

...