TypeScript Advanced

Back

Loading concept...

🎭 TypeScript Advanced: Teaching Your Code to Speak Clearly

The Magical Translator Analogy: Imagine you have a super-smart robot helper. But this robot only understands instructions when you’re VERY specific. TypeScript is like giving your robot a special dictionary that says “this button click means THIS” or “this box can only hold numbers, not words.” The more specific you are, the fewer mistakes your robot makes!


🎣 Typing Hooks: Labeling Your Magic Boxes

Think of React hooks like magic boxes that remember things for you. But these boxes need labels so they know what to hold!

useState: The Memory Box

Imagine a box that remembers a number for you:

// Tell the box: "You hold numbers!"
const [age, setAge] = useState<number>(0);

// Tell the box: "You might hold a user or nothing"
const [user, setUser] = useState<User | null>(null);

Why labels matter:

  • Without labels, the box gets confused
  • With labels, it stops you from putting a cat in the “numbers only” box

useEffect: The Action Timer

useEffect(() => {
  // This runs after your component appears
  document.title = "Hello!";

  // Return a cleanup function (optional)
  return () => {
    document.title = "Goodbye!";
  };
}, []); // Empty array = run once

useReducer: The Smart Decision Maker

type State = { count: number };
type Action =
  | { type: 'add'; amount: number }
  | { type: 'reset' };

function reducer(state: State, action: Action): State {
  switch (action.type) {
    case 'add':
      return { count: state.count + action.amount };
    case 'reset':
      return { count: 0 };
  }
}

const [state, dispatch] = useReducer(reducer, { count: 0 });
graph TD A["Action Arrives"] --> B{What type?} B -->|add| C["Add amount to count"] B -->|reset| D["Set count to zero"] C --> E["New State"] D --> E

🎯 Typing Events: Naming Your Actions

When you click a button or type in a box, events happen. TypeScript wants to know EXACTLY what kind of event!

Button Clicks

// The click event knows about buttons
function handleClick(e: React.MouseEvent<HTMLButtonElement>) {
  console.log("Button clicked!");
  e.preventDefault(); // Stop default behavior
}

<button onClick={handleClick}>Click Me!</button>

Typing in Input Boxes

// The change event knows about inputs
function handleChange(e: React.ChangeEvent<HTMLInputElement>) {
  const value = e.target.value; // TypeScript knows this is a string!
  console.log("You typed:", value);
}

<input onChange={handleChange} />

Form Submissions

function handleSubmit(e: React.FormEvent<HTMLFormElement>) {
  e.preventDefault(); // Don't reload the page!
  console.log("Form sent!");
}

<form onSubmit={handleSubmit}>
  <button type="submit">Send</button>
</form>

Common Event Types Cheat List

Event Type When It Happens
Click MouseEvent<HTMLButtonElement> Button pressed
Type ChangeEvent<HTMLInputElement> Text entered
Submit FormEvent<HTMLFormElement> Form sent
Key KeyboardEvent<HTMLInputElement> Key pressed

📍 Typing Refs: Pointing at Real Things

Refs are like putting a sticky note on something so you can find it later. But you need to say WHAT you’re putting the note on!

Pointing at HTML Elements

// "I'm pointing at an input box (or nothing yet)"
const inputRef = useRef<HTMLInputElement>(null);

function focusInput() {
  // The "?" means "only if it exists"
  inputRef.current?.focus();
}

return <input ref={inputRef} />;

Storing Values That Don’t Trigger Updates

// Keep a timer ID without re-rendering
const timerRef = useRef<number>(0);

useEffect(() => {
  timerRef.current = window.setInterval(() => {
    console.log("Tick!");
  }, 1000);

  return () => clearInterval(timerRef.current);
}, []);
graph TD A["Create Ref"] --> B["Point to Element"] B --> C["Access via .current"] C --> D{Does it exist?} D -->|Yes| E["Use it!"] D -->|No| F["Do nothing safely"]

đź§© Generic Components: One Size Fits Many

Imagine a gift box that can hold ANY type of gift, but once you say “this box is for toys,” it only accepts toys!

The Dropdown That Works for Anything

// T is a placeholder for "any type"
type DropdownProps<T> = {
  items: T[];
  onSelect: (item: T) => void;
  renderItem: (item: T) => string;
};

function Dropdown<T>(props: DropdownProps<T>) {
  return (
    <select onChange={(e) => {
      const index = Number(e.target.value);
      props.onSelect(props.items[index]);
    }}>
      {props.items.map((item, i) => (
        <option key={i} value={i}>
          {props.renderItem(item)}
        </option>
      ))}
    </select>
  );
}

Using the Generic Dropdown

// For strings
<Dropdown
  items={["Apple", "Banana", "Cherry"]}
  onSelect={(fruit) => console.log(fruit)}
  renderItem={(fruit) => fruit}
/>

// For objects
type User = { id: number; name: string };

<Dropdown<User>
  items={[{ id: 1, name: "Alice" }]}
  onSelect={(user) => console.log(user.id)}
  renderItem={(user) => user.name}
/>

A List Component That Shows Anything

interface ListProps<T> {
  items: T[];
  renderItem: (item: T) => React.ReactNode;
}

function List<T>({ items, renderItem }: ListProps<T>) {
  return <ul>{items.map(renderItem)}</ul>;
}

🛠️ Utility Types: TypeScript’s Magic Wand

TypeScript has built-in tools that transform types. Think of them as magic spells!

Partial: “Maybe Some, Maybe None”

Makes all properties optional:

type User = {
  name: string;
  age: number;
  email: string;
};

// Now all fields are optional!
type PartialUser = Partial<User>;

// This is now valid:
const update: PartialUser = { name: "Bob" };

Required: “Everything, No Exceptions”

Makes all properties required:

type MaybeUser = {
  name?: string;
  age?: number;
};

// Now ALL fields are required!
type FullUser = Required<MaybeUser>;

Pick: “I Only Want These”

Select specific properties:

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

// Only id and name
type PublicUser = Pick<User, 'id' | 'name'>;

Omit: “Everything Except These”

Remove specific properties:

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

// Everything except password
type SafeUser = Omit<User, 'password'>;

Record: “A Dictionary of Things”

Create an object type with specific keys and values:

// Keys are strings, values are numbers
type Scores = Record<string, number>;

const gameScores: Scores = {
  "level1": 100,
  "level2": 250
};

ReturnType: “What Does This Function Give Back?”

function getUser() {
  return { name: "Alice", age: 30 };
}

// Automatically figures out the return type!
type User = ReturnType<typeof getUser>;
// Result: { name: string; age: number }
graph TD A["Original Type"] --> B{Which Utility?} B -->|Partial| C["All Optional"] B -->|Required| D["All Required"] B -->|Pick| E["Keep Some"] B -->|Omit| F["Remove Some"] B -->|Record| G["Key-Value Map"]

🎮 Putting It All Together

Here’s a mini-app using EVERYTHING we learned:

// Utility types for user
type User = {
  id: number;
  name: string;
  email: string;
};
type UserPreview = Pick<User, 'id' | 'name'>;

// Generic list component
function UserList<T extends UserPreview>({
  users,
  onSelect
}: {
  users: T[];
  onSelect: (user: T) => void;
}) {
  return (
    <ul>
      {users.map(user => (
        <li key={user.id} onClick={() => onSelect(user)}>
          {user.name}
        </li>
      ))}
    </ul>
  );
}

// Main component with typed hooks and events
function App() {
  const [selected, setSelected] = useState<User | null>(null);
  const inputRef = useRef<HTMLInputElement>(null);

  const handleClick = (e: React.MouseEvent<HTMLButtonElement>) => {
    inputRef.current?.focus();
  };

  return (
    <div>
      <input ref={inputRef} />
      <button onClick={handleClick}>Focus</button>
      <UserList
        users={[{ id: 1, name: "Alice", email: "a@b.c" }]}
        onSelect={setSelected}
      />
    </div>
  );
}

🌟 Key Takeaways

  1. Typing Hooks = Tell your magic boxes what they can hold
  2. Typing Events = Name your actions precisely
  3. Typing Refs = Point clearly at real things
  4. Generic Components = Build reusable pieces that work with any type
  5. Utility Types = Transform types with magic spells

đź’ˇ Remember: TypeScript is your friend, not your enemy. It catches mistakes BEFORE they happen, like a spell-checker for your code logic!


You’re now a TypeScript wizard! Go forth and type safely! 🧙‍♂️✨

Loading story...

Story - Premium Content

Please sign in to view this story and start learning.

Upgrade to Premium to unlock full access to all stories.

Stay Tuned!

Story is coming soon.

Story Preview

Story - Premium Content

Please sign in to view this concept and start learning.

Upgrade to Premium to unlock full access to all content.