Liskov Substitution Principle (LSP)

Liskov Substitution Principle (LSP)

REACT NATIVE HUB
  • Definition: Objects or components should be replaceable with instances of their subtypes without altering the correctness of the program.
  • In React: When creating components or extending them, ensure they can be used interchangeably without breaking the application.

Not following LSP: In this example, incorrect use of interface methods and not following the base interface for the same type of component violates the LSP principle.

// ❌ BAD EXAMPLE - Violating LSP
interface BadBaseButton {
  onClick: () => void;
  text: string;  // Restricts to string only
}

const BadBaseButton: React.FC<BadBaseButton> = ({ onClick, text }) => (
  <button onClick={onClick}>{text}</button>
);

// Violates LSP by changing prop structure and behavior
interface BadPrimaryButton {
  label: string;  // Different prop name
  onAction: (e: React.MouseEvent) => Promise<void>;  // Different type
}

const BadPrimaryButton: React.FC<BadPrimaryButton> = ({ label, onAction }) => {
  const handleClick = async (e: React.MouseEvent) => {
    await onAction(e);
  };

  return <button onClick={handleClick}>{label.toUpperCase()}</button>;
};

// Usage shows incompatibility
const BadExample: React.FC = () => {
  const handleClick = () => console.log('clicked');

  return (
    <div>
      <BadBaseButton
        onClick={handleClick}
        text="Click me"
      />

      {/* Won't work! Different props and behavior */}
      <BadPrimaryButton
        label="Click me"
        onAction={async (e) => console.log('clicked')}
      />
    </div>
  );
};

Following LSP: It helps to ensure base props are extended consistently, the same onClick type throughout, components are interchangeable & add features without breaking the base contract.

// ✅ GOOD EXAMPLE - Following LSP
interface GoodBaseButtonProps {
  onClick: () => void;
  children: React.ReactNode;
}

const GoodBaseButton: React.FC<GoodBaseButtonProps> = ({ onClick, children }) => (
  <button onClick={onClick}>{children}</button>
);

// Properly extends base props
interface GoodPrimaryButtonProps extends GoodBaseButtonProps {
  variant?: 'solid' | 'outline';  // Optional additional prop
}

const GoodPrimaryButton: React.FC<GoodPrimaryButtonProps> = ({
  onClick,
  children,
  variant = 'solid'
}) => {
  const className = variant === 'solid' ? 'bg-blue-500' : 'border-blue-500';

  return (
    <button onClick={onClick} className={className}>
      {children}
    </button>
  );
};

// Usage shows compatibility
const GoodExample: React.FC = () => {
  const handleClick = () => console.log('clicked');

  return (
    <div>
      {/* Both components can use the same handler */}
      <GoodBaseButton onClick={handleClick}>
        Click me
      </GoodBaseButton>

      <GoodPrimaryButton onClick={handleClick} variant="solid">
        Click me
      </GoodPrimaryButton>
    </div>
  );
};




Report Page