no-excess-jsx-props
Report statically known fields spread outside a resolved component props contract.
Why
A spread can forward unrelated data even when structural typing accepts the larger object. Changing its annotation does not remove runtime fields.
Fix
Forward the declared fields explicitly or review the receiving contract. A projection changes object identity and allocations; this rule never constructs one automatically.
Examples
declare module "react/jsx-runtime" { export namespace JSX { interface Element {} interface IntrinsicElements { span: { children?: unknown }; } }}export {};const name = "Ada";const Avatar = ({ displayName }: { displayName: string }) => ( <span>{`${displayName}`}</span>);const element = <Avatar {...{ displayName: name, email: "unused" }} />;{ "compilerOptions": { "strict": true, "target": "ESNext", "module": "ESNext", "moduleResolution": "Bundler", "jsx": "react-jsx" }}declare module "react/jsx-runtime" { export namespace JSX { interface Element {} interface IntrinsicElements { span: { children?: unknown }; } }}export {};let element: any;const opaque = { toString() { return element.props.email; },};const name = opaque as unknown as string;const Avatar = ({ displayName }: { displayName: string }) => ( <span>{`${displayName}`}</span>);element = <Avatar {...{ displayName: name, email: "needed" }} />;{ "compilerOptions": { "strict": true, "target": "ESNext", "module": "ESNext", "moduleResolution": "Bundler", "jsx": "react-jsx" }}declare module "react/jsx-runtime" { export namespace JSX { interface Element {} interface IntrinsicElements { span: { children?: unknown }; } }}export {};const Avatar = ({ displayName }: { displayName: string }) => <span>{displayName}</span>;const element = <Avatar {...{ displayName: "Ada", email: "unused" }} />;const summary = { displayName: (element as { props: { displayName: string } }).props.displayName,};export { summary };{ "compilerOptions": { "strict": true, "target": "ESNext", "module": "ESNext", "moduleResolution": "Bundler", "jsx": "react-jsx" }}declare module "react/jsx-runtime" { export namespace JSX { interface Element {} interface IntrinsicElements { span: { children?: unknown }; } }}export {};declare function inspect(value: unknown): void;const Avatar = ({ displayName }: { displayName: string }) => <span>{displayName}</span>;const element = <Avatar {...{ displayName: "Ada", email: "needed" }} />;inspect(element);{ "compilerOptions": { "strict": true, "target": "ESNext", "module": "ESNext", "moduleResolution": "Bundler", "jsx": "react-jsx" }}declare module "react/jsx-runtime" { export namespace JSX { interface Element {} interface IntrinsicElements { span: { children?: unknown }; } }}export {};const settings = { defaultProps: { email: "fallback" } };settings.defaultProps = { email: "updated" };const Avatar = ({ displayName }: { displayName: string }) => <span>{displayName}</span>;const element = <Avatar {...{ displayName: "Ada", email: "unused" }} />;{ "compilerOptions": { "strict": true, "target": "ESNext", "module": "ESNext", "moduleResolution": "Bundler", "jsx": "react-jsx" }}declare module "react/jsx-runtime" { export namespace JSX { interface Element {} interface IntrinsicElements { span: { children?: unknown }; } }}export {};const target = { ref: 0 };const Avatar = ({ displayName }: { displayName: string }) => <span>{displayName}</span>;(Avatar as unknown as { defaultProps: { email: string } }).defaultProps = { get email() { target.ref = 1; return "fallback"; },};const element = <Avatar {...{ displayName: "Ada", email: "needed" }} />;const observation = target.ref;export { observation };{ "compilerOptions": { "strict": true, "target": "ESNext", "module": "ESNext", "moduleResolution": "Bundler", "jsx": "react-jsx" }}declare module "react/jsx-runtime" { export namespace JSX { interface Element {} interface IntrinsicElements { span: { children?: unknown }; } }}export {};const Avatar = ({ displayName }: { displayName: string }) => <span>{displayName}</span>;const avatar = <Avatar {...{ displayName: "Ada", email: "ada@example.test" }} />;{ "compilerOptions": { "strict": true, "target": "ESNext", "module": "ESNext", "moduleResolution": "Bundler", "jsx": "react-jsx" }}declare module "react/jsx-runtime" { export namespace JSX { interface Element {} interface IntrinsicElements { span: { children?: unknown }; } }}export {};const Avatar = ({ displayName }: { displayName: string }) => <span>{displayName}</span>;const avatar = <Avatar displayName="Ada" />;{ "compilerOptions": { "strict": true, "target": "ESNext", "module": "ESNext", "moduleResolution": "Bundler", "jsx": "react-jsx" }}declare module "react/jsx-runtime" { export namespace JSX { interface Element {} interface IntrinsicElements { span: { children?: unknown }; } }}export {};const target = { ref: null };target.ref = null;const Avatar = ({ displayName }: { displayName: string }) => <span>{displayName}</span>;const element = <Avatar {...{ displayName: "Ada", email: "unused" }} />;{ "compilerOptions": { "strict": true, "target": "ESNext", "module": "ESNext", "moduleResolution": "Bundler", "jsx": "react-jsx" }}declare module "react/jsx-runtime" { export namespace JSX { interface Element {} interface IntrinsicElements { span: { children?: unknown }; } }}export {};let element: any;const Avatar = ({ displayName }: { displayName: string }) => <span>{displayName}</span>;element = <Avatar {...{ displayName: "Ada", email: "needed" }} />;Object.defineProperty(Object.prototype, "ref", { configurable: true, get() { Object.defineProperty(this, "children", { configurable: true, value: element.props.email, }); return null; },});{ "compilerOptions": { "strict": true, "target": "ESNext", "module": "ESNext", "moduleResolution": "Bundler", "jsx": "react-jsx" }}