Advanced React Clean Code - Defining Props with Functional Component and TypeScript

Advanced React Clean Code - Defining Props with Functional Component and TypeScript

24/05/2024devSaul Vo


In React with TypeScript, defining props for functional components not only makes your code cleaner, easier to read, but also takes advantage of the power of type-checking to avoid common errors. Here are some tips to define props effectively when using functional components in conjunction with TypeScript:

1. Use Interface or Type Aliases:

Defines the type of the props through interface or type. This ensures that you and your teammates always transmit the right type of data and data structure needed for each component.

interface UserProps {
  name: string;
  age: number;
  isActive: boolean;
}

const User: React.FC<UserProps> = ({ name, age, isActive }) => {
  // Component logic...
};

Or:

type UserProps = {
  name: string;
  age: number;
  isActive: boolean;
};

const User: React.FC<UserProps> = ({ name, age, isActive }) => {
  // Component logic...
};

2. Default Props through Destructuring Assignment:

Set the default value for the props directly through the destructuring assignment in the function signature of the component. This keeps your functions clean and the default values clearly applied.

const User: React.FC<UserProps> = ({ name, age, isActive = true }) => {
  // Component logic...
};

3. Identify Custom Function Props:

Sometimes, not all props are needed. Use the ? mark after the variable name to mark the prop as optional.

interface UserProps {
  name: string;
  age?: number; // age isn't always necessary.
}

4. Definition of Complex Type:

For complex data types such as array or object, you can clearly define them in a separate interface or type.

interface Address {
  street: string;
  city: string;
}

interface UserProps {
  name: string;
  address: Address;
  handleClick: (id: number) => void; // Function
}

// Used in component:
const User: React.FC<UserProps> = ({ name, address, handleClick }) => {
  // ...
};

5. Use Generic Types for Flexible Props:

Generic types in TypeScript help you build components that can work with different types of data without losing the power of type-checking.

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

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

6. Use Utility Types to Control Props Better:

TypeScript offers a range of utility types that help you handle complex cases when working with props. For example, you can use Partial<T> to create a type where all the properties of the type T become optional, or Readonly<T > to define a props that cannot change the value after being created.

type UserProps = {
  name: string;
  age: number;
};

const UserComponent: React.FC<Partial<UserProps>> = ({ name, age }) => {
  // Mọi props đều là optional
  // component logic
  return (
    // JSX goes here...
  );
};

7. Inheritance and Composite Types:

TypeScript allows you to inherit and combine types. This is useful when you want to create a props set that will be reused on many different components or when you need to extend the props from a third-party component.

type BaseProps = {
  className?: string;
};

type UserProps = BaseProps & {
  name: string;
  age: number;
};

const UserComponent: React.FC<UserProps> = ({ className, name, age }) => {
  // component logic
  return (
    // JSX goes here...
  );
};

Using TypeScript requires some solid understanding of concepts such as generics, unions, intersections, and types. Good luck, and remember, tools never make a worker.