React Curriculum

Typing Components, Props, Children & Events

Easy100% Free~25 mins#react#typescript#props#events#reactnode#typing
Interview Answer (30-Second Summary)

In modern React TypeScript, type components as standard functions with typed prop interfaces rather than React.FC. Type children with React.ReactNode, and use specific synthetic event types like React.MouseEvent<HTMLButtonElement> or React.ChangeEvent<HTMLInputElement> for full type safety.

Key Learning Objectives
✓

Compare standard function typing vs React.FC and explain why React.FC is discouraged.

✓

Differentiate ReactNode, ReactElement, and JSX.Element for typing children and render props.

✓

Type DOM event handlers accurately with synthetic event generics and HTML element targets.

✓

Apply ComponentPropsWithoutRef to extend native HTML button, input, and div elements safely.

The Interview Problem & Context

Provide production TypeScript signatures for a custom Button component, an Input with event handlers, and explain why `React.ReactNode` is preferred over `JSX.Element` for children.

1import React, { ComponentPropsWithoutRef, ReactNode, MouseEvent, ChangeEvent } from 'react';
2
3// 1. Extending native HTML button props cleanly
4interface ButtonProps extends ComponentPropsWithoutRef<'button'> {
5 variant?: 'primary' | 'secondary' | 'danger';
6 isLoading?: boolean;
7 children: ReactNode; // Accepts JSX, strings, numbers, fragments, portals, or null
8}
9
10// 2. Idiomatic Function Component (Avoid React.FC)
11export function CustomButton({
12 variant = 'primary',
13 isLoading = false,
14 children,
15 onClick,
16 ...nativeProps
17}: ButtonProps) {
18 const handleClick = (e: MouseEvent<HTMLButtonElement>) => {
19 if (isLoading) {
20 e.preventDefault();
21 return;
22 }
23 onClick?.(e);
24 };
25
26 return (
27 <button {...nativeProps} onClick={handleClick} disabled={isLoading || nativeProps.disabled}>
28 {isLoading ? 'Loading...' : children}
29 </button>
30 );
31}
32
33// 3. Typing Form Inputs and Change Events
34interface SearchInputProps {
35 value: string;
36 onChange: (e: ChangeEvent<HTMLInputElement>) => void;
37 onSearchSubmit: (query: string) => void;
38}
39
40export function SearchInput({ value, onChange, onSearchSubmit }: SearchInputProps) {
41 return (
42 <input
43 type="text"
44 value={value}
45 onChange={onChange}
46 onKeyDown={(e: React.KeyboardEvent<HTMLInputElement>) => {
47 if (e.key === 'Enter') onSearchSubmit(value);
48 }}
49 />
50 );
51}
Deep Architectural Explanation

Idiomatic React Component Typing

1. Why Avoid React.FC (React.FunctionComponent):

  • In older React versions, React.FC automatically added an implicit children?: ReactNode prop, breaking components that were never intended to receive children.
  • It complicates generic components (function List<T>()).
  • Writing a standard function with a typed prop parameter is simpler and more idiomatic:
    export function MyButton(props: ButtonProps) {}

2. ReactNode vs ReactElement vs JSX.Element:

TypeAllowed ValuesWhen to Use
React.ReactNodeJSX.Element, string, number, boolean, null, undefined, Iterable<ReactNode>Best for children prop and slot props.
React.ReactElementValid React element object created via React.createElementWhen component MUST return or receive a single JSX element.
JSX.ElementReactElement with any props and any typeReturned by JSX expressions; generally use ReactElement instead.

3. Typing Events:

Always use React SyntheticEvent generics:

  • React.MouseEvent<HTMLButtonElement>
  • React.ChangeEvent<HTMLInputElement>
  • React.KeyboardEvent<HTMLInputElement>
  • React.FormEvent<HTMLFormElement>
Common Interview Traps & Pitfalls
✕

Typing event handlers as `(e: any) => void` instead of using React synthetic event generics.

✕

Typing children as `JSX.Element`, which rejects plain strings, numbers, or null.

✕

Using `React.FC` which creates unnecessary type indirection.

Senior Interviewer Follow-Up Probes
?

How does `ComponentPropsWithoutRef<"button">` differ from `ButtonHTMLAttributes<HTMLButtonElement>`?

?

How do you type a component that accepts only a single valid React child element?

?

How do you type forwardRef components in TypeScript without using any?

Frequently Asked Interview Questions
Why is React.FC discouraged in modern React TypeScript?

React.FC originally implicitly included children?: ReactNode on all components, making it impossible to enforce that a component takes no children. It also makes generic parameters cumbersome and provides little benefit.

ReactNode is a broad union that includes strings, numbers, booleans, null, undefined, ReactElements, and arrays of ReactNodes. JSX.Element is specifically an object representing a JSX expression and rejects strings or numbers.

Use ComponentPropsWithoutRef<"button">. It includes all standard HTML attributes (disabled, type, aria-*, id, etc.) without having to declare them manually.

React.ChangeEventHandler<HTMLInputElement> or a function accepting (event: React.ChangeEvent<HTMLInputElement>) => void.

In React 19, ref is a regular prop typed as ref?: React.Ref<HTMLButtonElement>. In React 18 and earlier, forwardRef<HTMLButtonElement, Props> was required.

Yes, returning null is valid in React and TypeScript represents this cleanly when return type is ReactNode or ReactElement | null.