Skip to main content
ESLint Interlace
Plugin: react-featuresRules

no-kind-prop-discriminator

Ban `type`/`kind` string-union props that select between rendered trees (R11)

Part of: componentApi preset (opt-in — not in recommended)

Ban the type: "A" | "B" kind-prop pattern when the value is intended to switch the rendered tree. This heuristic detects TypeScript interfaces / type aliases where a property named type or kind carries a string-literal union of 2 or more members, signalling a component that renders different element trees per variant. The correct fix is to split into sub-components (Foo.A, Foo.B).

Note: variant is not flagged by default because the dominant CVA usage only switches className / role, not the element tree.

Why This Matters

IssueImpactSolution
Conditional tree complexityOne component renders N different trees, inflating its test surfaceSplit into sub-components
Type unsafetyNarrowing on type at the call site is brittleLet TypeScript discriminate on the import name instead
API bloatA single component accumulates props from multiple logical variantsSeparate components with focused prop surfaces

Examples

Incorrect

interface AlertProps {
  type: "error" | "warning" | "info";  // ❌ R11 — kind-prop discriminator
  message: string;
}

function Alert({ type, message }: AlertProps) {
  if (type === "error") return <div className="text-red-600">{message}</div>;
  if (type === "warning") return <div className="text-yellow-600">{message}</div>;
  return <div className="text-blue-600">{message}</div>;
}

Correct

// Split into sub-components
function AlertError({ message }: { message: string }) {
  return <div className="text-red-600">{message}</div>;
}

function AlertWarning({ message }: { message: string }) {
  return <div className="text-yellow-600">{message}</div>;
}

// Or as a namespace
Alert.Error = AlertError;
Alert.Warning = AlertWarning;

Configuration

// eslint.config.mjs
export default [
  {
    rules: {
      "react-features/no-kind-prop-discriminator": "error",
    },
  },
];

This rule is part of eslint-plugin-react-features.