Conversation
WalkthroughThis PR performs a comprehensive type system refactoring, introducing new public axis type aliases ( Changes
Estimated code review effort🎯 4 (Complex) | ⏱️ ~45–60 minutes
Possibly related PRs
Suggested labels
Suggested reviewers
Pre-merge checks and finishing touches❌ Failed checks (2 warnings, 1 inconclusive)
✨ Finishing touches
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 3
🧹 Nitpick comments (5)
src/util/DataUtils.ts (1)
16-19: Type guard semantics are misleading.The type guard
value is numbernarrows the type tonumberwhenisNanreturnstrue. While technically correct (NaN istypeof number), this is semantically confusing because:
- When
isNan(x)returnstrue,xis NaN—usually an unwanted value- Callers likely want to narrow to a valid number, not confirm a NaN
The existing usage in
isNumber(line 25) works correctly because it uses!isNan(value), but the type guard doesn't help there since negating a type guard doesn't narrow.Consider keeping this as a plain
booleanreturn, or if a type guard is needed for specific use cases, document the intent clearly.-export const isNan = (value: unknown): value is number => { +export const isNan = (value: unknown): boolean => { // eslint-disable-next-line eqeqeq return typeof value == 'number' && value != +value; };src/util/ChartUtils.ts (1)
649-649: Consider using nullish coalescing for precision.Using
|| 0replaces any falsy value (including0) with0. While functionally equivalent in this case (0 - 0 = 0),?? 0is more precise and conveys intent better.- bandSize = Math.min((cur?.coordinate || 0) - (prev?.coordinate || 0), bandSize); + bandSize = Math.min((cur?.coordinate ?? 0) - (prev?.coordinate ?? 0), bandSize);src/state/selectors/axisSelectors.ts (3)
298-399:itemAxisPredicateand cartesian item selectors handle expanded axis types reasonably.Allowing
itemAxisPredicateand downstream selectors (selectCartesianItemsSettings,selectCartesianGraphicalItemsData, etc.) to acceptAllAxisTypesis fine: for non‑cartesian axes (angle/radius/z), the predicate simply filters everything out, which matches expectations.If you want to make this clearer and tighten types, consider constraining
axisTypeto'xAxis' | 'yAxis' | 'zAxis'for these cartesian‑only selectors and predicates, while still usingAllAxisTypesat higher‑level call sites. That would better document intent but isn’t strictly required.
689-751:getDomainDefinitionworks, but the final fallback is slightly redundant.Using
AllAxisSettingsingetDomainDefinitionand drivingselectDomainDefinition/selectDomainFromUserPreferenceoffselectBaseAxisunifies axis handling nicely. The tick‑based domain inference whendomainis unset is also a good addition.Minor clean‑up opportunity: after the tick‑based branch, the final line:
return axisSettings?.domain ?? defaultNumericDomain;can never hit a non‑null
domain(that was returned earlier), so this could be simplified to justdefaultNumericDomainfor clarity. Optional, not blocking.
886-933: Reference‑element filters and domain combiners are consistent, but only meaningful for cartesian axes.
filterReferenceElements,combineDotsDomain,combineAreasDomain, andcombineLinesDomainnow acceptAllAxisTypes/RenderableAxisType, but practically onlyxAxis/yAxisproduce meaningful results. For other axis types, filters fall through to the y‑axis branch or end up with empty collections, which then propagate asundefineddomains and are safely ignored bymergeDomains.If you want to make this intent explicit, consider narrowing the axis‑type parameters on
filterReferenceElementsand theselectReference*ByAxisselectors to'xAxis' | 'yAxis'. Behavior is otherwise sound.Also applies to: 934-961, 984-997
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (16)
src/context/useTooltipAxis.ts(1 hunks)src/state/selectors/axisSelectors.ts(59 hunks)src/state/selectors/combiners/combineActiveLabel.ts(1 hunks)src/state/selectors/combiners/combineActiveTooltipIndex.ts(1 hunks)src/state/selectors/combiners/combineCoordinateForDefaultIndex.ts(1 hunks)src/state/selectors/combiners/combineTooltipPayloadConfigurations.ts(2 hunks)src/state/selectors/rootPropsSelectors.ts(1 hunks)src/state/selectors/selectTooltipAxisType.ts(1 hunks)src/state/selectors/selectors.ts(3 hunks)src/state/selectors/tooltipSelectors.ts(3 hunks)src/util/ChartUtils.ts(8 hunks)src/util/DataUtils.ts(1 hunks)src/util/getActiveCoordinate.ts(6 hunks)test/cartesian/YAxis/YAxis.ticks.spec.tsx(2 hunks)test/chart/ScatterChart.spec.tsx(0 hunks)test/state/selectors/axisSelectors.spec.tsx(5 hunks)
💤 Files with no reviewable changes (1)
- test/chart/ScatterChart.spec.tsx
🧰 Additional context used
📓 Path-based instructions (7)
**/*.{ts,tsx}
📄 CodeRabbit inference engine (CONTRIBUTING.md)
**/*.{ts,tsx}: Never useanytype (implicit or explicit) in TypeScript code
Preferunknownoveranyand refine the type in TypeScript
Type function parameters and return values explicitly in TypeScript, do not rely on implicit any or inference; exceptions are React components and trivial functions
Do not useastype assertions in TypeScript; the only exception isas const
Files:
src/state/selectors/combiners/combineActiveTooltipIndex.tssrc/util/DataUtils.tssrc/context/useTooltipAxis.tstest/cartesian/YAxis/YAxis.ticks.spec.tsxsrc/state/selectors/rootPropsSelectors.tssrc/state/selectors/combiners/combineCoordinateForDefaultIndex.tssrc/state/selectors/tooltipSelectors.tssrc/util/getActiveCoordinate.tssrc/state/selectors/combiners/combineActiveLabel.tssrc/state/selectors/combiners/combineTooltipPayloadConfigurations.tssrc/util/ChartUtils.tssrc/state/selectors/selectTooltipAxisType.tstest/state/selectors/axisSelectors.spec.tsxsrc/state/selectors/axisSelectors.tssrc/state/selectors/selectors.ts
**/*.{js,ts,tsx}
📄 CodeRabbit inference engine (CONTRIBUTING.md)
Ensure code lints by running
npm run lintand follows Airbnb's Style Guide
Files:
src/state/selectors/combiners/combineActiveTooltipIndex.tssrc/util/DataUtils.tssrc/context/useTooltipAxis.tstest/cartesian/YAxis/YAxis.ticks.spec.tsxsrc/state/selectors/rootPropsSelectors.tssrc/state/selectors/combiners/combineCoordinateForDefaultIndex.tssrc/state/selectors/tooltipSelectors.tssrc/util/getActiveCoordinate.tssrc/state/selectors/combiners/combineActiveLabel.tssrc/state/selectors/combiners/combineTooltipPayloadConfigurations.tssrc/util/ChartUtils.tssrc/state/selectors/selectTooltipAxisType.tstest/state/selectors/axisSelectors.spec.tsxsrc/state/selectors/axisSelectors.tssrc/state/selectors/selectors.ts
src/**/*.{ts,tsx}
📄 CodeRabbit inference engine (AGENTS.md)
Do not hardcode any strings or formatting choices in library code; users should provide localized strings as desired
Files:
src/state/selectors/combiners/combineActiveTooltipIndex.tssrc/util/DataUtils.tssrc/context/useTooltipAxis.tssrc/state/selectors/rootPropsSelectors.tssrc/state/selectors/combiners/combineCoordinateForDefaultIndex.tssrc/state/selectors/tooltipSelectors.tssrc/util/getActiveCoordinate.tssrc/state/selectors/combiners/combineActiveLabel.tssrc/state/selectors/combiners/combineTooltipPayloadConfigurations.tssrc/util/ChartUtils.tssrc/state/selectors/selectTooltipAxisType.tssrc/state/selectors/axisSelectors.tssrc/state/selectors/selectors.ts
**/*.{ts,tsx,js,jsx}
📄 CodeRabbit inference engine (DEVELOPING.md)
All imports from
rechartsmust use the public API entry point; imports from internal paths likerecharts/types/*orrecharts/src/*are not allowed
Files:
src/state/selectors/combiners/combineActiveTooltipIndex.tssrc/util/DataUtils.tssrc/context/useTooltipAxis.tstest/cartesian/YAxis/YAxis.ticks.spec.tsxsrc/state/selectors/rootPropsSelectors.tssrc/state/selectors/combiners/combineCoordinateForDefaultIndex.tssrc/state/selectors/tooltipSelectors.tssrc/util/getActiveCoordinate.tssrc/state/selectors/combiners/combineActiveLabel.tssrc/state/selectors/combiners/combineTooltipPayloadConfigurations.tssrc/util/ChartUtils.tssrc/state/selectors/selectTooltipAxisType.tstest/state/selectors/axisSelectors.spec.tsxsrc/state/selectors/axisSelectors.tssrc/state/selectors/selectors.ts
test/**/*.spec.{ts,tsx}
📄 CodeRabbit inference engine (CONTRIBUTING.md)
Aim for 100% unit test code coverage when writing new code
Files:
test/cartesian/YAxis/YAxis.ticks.spec.tsxtest/state/selectors/axisSelectors.spec.tsx
test/**/*.{test,spec}.{ts,tsx}
📄 CodeRabbit inference engine (test/README.md)
test/**/*.{test,spec}.{ts,tsx}: Aim for 100% unit test code coverage when writing new code
Prefer to use thecreateSelectorTestCasehelper function when writing or modifying tests
Use theexpectLastCalledWithhelper function instead ofexpect(spy).toHaveBeenLastCalledWith(...)for better typing and autocompletion
Verify the number of selector calls using the spy object fromcreateSelectorTestCaseto spot unnecessary re-renders and improve performance
MockgetBoundingClientRectin tests using the helper function provided intest/helper/MockGetBoundingClientRect.ts
Usevi.useFakeTimers()in all tests due to Redux autoBatchEnhancer dependency on timers andrequestAnimationFrame
Callvi.runOnlyPendingTimers()to advance timers after renders when not usingcreateSelectorTestCasehelper, and avoidvi.runAllTimers()to prevent infinite loops
UseuserEvent.setup({ advanceTimers: vi.runOnlyPendingTimers })or theuserEventSetuphelper function fromtest/helper/userEventSetup.tswhen creating userEvent instances
When testing tooltips on hover, usevi.runOnlyPendingTimers()after eachuserEvent.hover()call or use theshowTooltiphelper function fromtooltipTestHelpers.tsto account for requestAnimationFrame delays
Files:
test/cartesian/YAxis/YAxis.ticks.spec.tsxtest/state/selectors/axisSelectors.spec.tsx
**/*.spec.{ts,tsx}
📄 CodeRabbit inference engine (AGENTS.md)
When running unit tests, prefer to run a single test file using
npm run test -- path/to/TestFile.spec.tsxrather than running all tests withnpm test
Files:
test/cartesian/YAxis/YAxis.ticks.spec.tsxtest/state/selectors/axisSelectors.spec.tsx
🧠 Learnings (8)
📚 Learning: 2025-11-23T13:30:10.395Z
Learnt from: PavelVanecek
Repo: recharts/recharts PR: 6669
File: www/src/docs/exampleComponents/ScatterChart/ScatterChartWithLabels.tsx:2-2
Timestamp: 2025-11-23T13:30:10.395Z
Learning: The `TooltipIndex` type from recharts is defined in `src/state/tooltipSlice.ts` but is not currently exported from the public API entry points. It should not be imported from `recharts/types/state/tooltipSlice` as this is an internal implementation path. An ESLint rule is needed to prevent regressions.
Applied to files:
src/state/selectors/combiners/combineActiveTooltipIndex.tssrc/context/useTooltipAxis.tssrc/state/selectors/rootPropsSelectors.tssrc/state/selectors/combiners/combineCoordinateForDefaultIndex.tssrc/state/selectors/tooltipSelectors.tssrc/state/selectors/combiners/combineActiveLabel.tssrc/state/selectors/combiners/combineTooltipPayloadConfigurations.tssrc/util/ChartUtils.tssrc/state/selectors/selectTooltipAxisType.tssrc/state/selectors/axisSelectors.tssrc/state/selectors/selectors.ts
📚 Learning: 2025-11-25T01:23:08.250Z
Learnt from: CR
Repo: recharts/recharts PR: 0
File: test/README.md:0-0
Timestamp: 2025-11-25T01:23:08.250Z
Learning: Applies to test/**/*.{test,spec}.{ts,tsx} : When testing tooltips on hover, use `vi.runOnlyPendingTimers()` after each `userEvent.hover()` call or use the `showTooltip` helper function from `tooltipTestHelpers.ts` to account for requestAnimationFrame delays
Applied to files:
src/state/selectors/combiners/combineActiveTooltipIndex.ts
📚 Learning: 2025-12-06T03:36:59.377Z
Learnt from: CR
Repo: recharts/recharts PR: 0
File: DEVELOPING.md:0-0
Timestamp: 2025-12-06T03:36:59.377Z
Learning: Applies to **/*.{ts,tsx,js,jsx} : All imports from `recharts` must use the public API entry point; imports from internal paths like `recharts/types/*` or `recharts/src/*` are not allowed
Applied to files:
src/state/selectors/rootPropsSelectors.tssrc/state/selectors/tooltipSelectors.tssrc/util/ChartUtils.tssrc/state/selectors/axisSelectors.ts
📚 Learning: 2025-11-25T01:23:08.250Z
Learnt from: CR
Repo: recharts/recharts PR: 0
File: test/README.md:0-0
Timestamp: 2025-11-25T01:23:08.250Z
Learning: Applies to test/**/*.{test,spec}.{ts,tsx} : Verify the number of selector calls using the spy object from `createSelectorTestCase` to spot unnecessary re-renders and improve performance
Applied to files:
test/state/selectors/axisSelectors.spec.tsxsrc/state/selectors/selectors.ts
📚 Learning: 2025-11-25T01:23:08.250Z
Learnt from: CR
Repo: recharts/recharts PR: 0
File: test/README.md:0-0
Timestamp: 2025-11-25T01:23:08.250Z
Learning: Applies to test/**/*.{test,spec}.{ts,tsx} : Prefer to use the `createSelectorTestCase` helper function when writing or modifying tests
Applied to files:
test/state/selectors/axisSelectors.spec.tsx
📚 Learning: 2025-11-25T01:23:08.250Z
Learnt from: CR
Repo: recharts/recharts PR: 0
File: test/README.md:0-0
Timestamp: 2025-11-25T01:23:08.250Z
Learning: Applies to test/**/*.{test,spec}.{ts,tsx} : Call `vi.runOnlyPendingTimers()` to advance timers after renders when not using `createSelectorTestCase` helper, and avoid `vi.runAllTimers()` to prevent infinite loops
Applied to files:
test/state/selectors/axisSelectors.spec.tsx
📚 Learning: 2025-11-25T01:23:08.250Z
Learnt from: CR
Repo: recharts/recharts PR: 0
File: test/README.md:0-0
Timestamp: 2025-11-25T01:23:08.250Z
Learning: Applies to test/**/*.{test,spec}.{ts,tsx} : Use the `expectLastCalledWith` helper function instead of `expect(spy).toHaveBeenLastCalledWith(...)` for better typing and autocompletion
Applied to files:
test/state/selectors/axisSelectors.spec.tsx
📚 Learning: 2025-11-19T14:08:01.728Z
Learnt from: PavelVanecek
Repo: recharts/recharts PR: 6659
File: www/src/components/GuideView/Performance/index.tsx:232-250
Timestamp: 2025-11-19T14:08:01.728Z
Learning: In Recharts version 3.4.2, object-as-prop optimizations were introduced to reduce unnecessary re-renders when new object references are passed as props. This affects the recommendation for the `react-perf/jsx-no-new-object-as-prop` ESLint rule.
Applied to files:
src/state/selectors/axisSelectors.ts
🧬 Code graph analysis (12)
src/state/selectors/combiners/combineActiveTooltipIndex.ts (1)
src/state/tooltipSlice.ts (1)
TooltipInteractionState(118-162)
test/cartesian/YAxis/YAxis.ticks.spec.tsx (1)
src/state/selectors/axisSelectors.ts (1)
RenderableAxisSettings(99-99)
src/state/selectors/rootPropsSelectors.ts (1)
src/state/store.ts (1)
RechartsRootState(23-38)
src/state/selectors/combiners/combineCoordinateForDefaultIndex.ts (1)
src/util/types.ts (1)
TickItem(803-808)
src/state/selectors/tooltipSelectors.ts (2)
src/state/selectors/axisSelectors.ts (1)
RenderableAxisSettings(99-99)src/state/selectors/selectTooltipAxisType.ts (1)
RenderableAxisType(12-12)
src/util/getActiveCoordinate.ts (1)
storybook/stories/data/Tick.ts (1)
ticks(16-16)
src/state/selectors/combiners/combineActiveLabel.ts (2)
src/util/types.ts (1)
TickItem(803-808)src/synchronisation/types.ts (1)
ActiveLabel(4-4)
src/state/selectors/combiners/combineTooltipPayloadConfigurations.ts (1)
src/util/types.ts (1)
TooltipEventType(955-955)
src/util/ChartUtils.ts (5)
src/state/selectors/axisSelectors.ts (1)
AxisRange(1457-1457)src/util/DataUtils.ts (1)
isNan(16-19)src/util/types.ts (2)
StackOffsetType(49-49)NumberDomain(708-708)src/util/getSliced.ts (1)
getSliced(1-9)src/util/isWellBehavedNumber.ts (1)
isWellBehavedNumber(1-3)
src/state/selectors/selectTooltipAxisType.ts (1)
src/state/store.ts (1)
RechartsRootState(23-38)
test/state/selectors/axisSelectors.spec.tsx (3)
src/state/store.ts (1)
RechartsRootState(23-38)src/state/selectors/axisSelectors.ts (1)
selectCalculatedXAxisPadding(1363-1373)test/helper/selectorTestHelpers.tsx (3)
shouldReturnUndefinedOutOfContext(9-20)shouldReturnFromInitialState(22-35)useAppSelectorWithStableTest(86-93)
src/state/selectors/axisSelectors.ts (3)
src/util/types.ts (1)
NumberDomain(708-708)src/state/selectors/selectTooltipAxisType.ts (3)
AllAxisTypes(7-7)RenderableAxisType(12-12)selectTooltipAxisType(14-30)src/state/selectors/combiners/combineAxisRangeWithReverse.ts (1)
combineAxisRangeWithReverse(4-15)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
- GitHub Check: Analyze (javascript-typescript)
🔇 Additional comments (49)
src/util/ChartUtils.ts (3)
337-372: Good defensive null-checks, but potential NaN propagation.The null-safety improvements (optional chaining, null checks) are solid. However, at lines 364 and 368, when
series1is NaN (detected at line 359), the code still assignspositive = series1ornegative = series1, which propagates NaN to subsequent iterations.Consider whether this is intended behavior or if the assignment should use
value(the already-sanitized fallback) instead:if (value >= 0) { col[0] = positive; col[1] = positive + value; - positive = series1; + positive = col[1]; } else { col[0] = negative; col[1] = negative + value; - negative = series1; + negative = col[1]; }This would mirror the pattern used in
offsetPositive(line 407).
432-450: LGTM!Good improvements:
- Stronger typing with
Record<StackOffsetType, OffsetAccessor>ensures compile-time coverage of all offset types- The
?? stackOffsetNonefallback at line 450 provides runtime safety for edge cases
595-606: LGTM!The added null guards and
isWellBehavedNumbervalidation improve robustness by:
- Safely skipping missing groups (lines 595-597)
- Filtering out malformed domain slices (NaN, Infinity) before aggregation (lines 603-605)
test/cartesian/YAxis/YAxis.ticks.spec.tsx (1)
7-21: LGTM!The type rename from
AxisWithTicksSettingstoRenderableAxisSettingsaligns with the PR's axis type migration. The test object structure correctly matches the new type definition.src/state/selectors/combiners/combineActiveTooltipIndex.ts (1)
55-64: LGTM!Making
tooltipInteractionoptionally undefined is a sensible defensive change. The implementation correctly handles this with optional chaining at line 61, returningnullwhen the interaction state is missing.src/state/selectors/rootPropsSelectors.ts (1)
8-8: This concern is unfounded. ThebarCategoryGapproperty is defined asnumber | string(not optional) inUpdatableChartOptionsand initialized with a default value ('10%') in the reducer. The return type ofstring | numberis correct and matches the actual state type; no narrowing or breaking change occurred.Likely an incorrect or invalid review comment.
src/state/selectors/combiners/combineActiveLabel.ts (1)
6-14: LGTM!The function signature and implementation correctly handle the case where
tooltipTicksis undefined. The optional chaining on line 14 safely guards against undefined array access, and the existing null checks foractiveIndexremain intact.test/state/selectors/axisSelectors.spec.tsx (6)
1129-1129: LGTM!The selector definition correctly passes the required
isPanorama: falseargument, aligning with the updatedselectCalculatedXAxisPaddingsignature.
1137-1137: LGTM!Test call updated to match the new selector arity.
1153-1153: LGTM!Consistent with the selector signature update.
1169-1169: LGTM!Consistent with the selector signature update.
1185-1185: LGTM!Consistent with the selector signature update.
1201-1201: LGTM!Consistent with the selector signature update.
src/state/selectors/tooltipSelectors.ts (3)
3-37: LGTM!Import of
RenderableAxisSettingscorrectly aligns with the type rename inaxisSelectors.ts.
81-81: LGTM!Import of
RenderableAxisTypecorrectly references the new type fromselectTooltipAxisType.ts.
314-323: LGTM!Function parameters correctly use the renamed types
RenderableAxisSettingsandRenderableAxisType, maintaining consistency with the broader type system refactor.src/context/useTooltipAxis.ts (2)
3-3: LGTM!Import correctly updated to use the renamed
RenderableAxisSettingstype.
6-6: LGTM!Return type correctly updated to
RenderableAxisSettings | undefined. This is a public API change that aligns with the broader type system refactor.src/state/selectors/selectTooltipAxisType.ts (2)
4-12: LGTM!The new type aliases provide a clear semantic distinction:
AllAxisTypesincludes all axes (includingzAxis)RenderableAxisTypeexcludeszAxissince it lacks ticks and is never renderedThe documentation comment on line 10 helpfully explains the rationale.
14-29: LGTM!The selector correctly returns
RenderableAxisTypesince the tooltip axis is always a rendered axis (never zAxis).src/state/selectors/combiners/combineTooltipPayloadConfigurations.ts (2)
7-7: LGTM!Parameter type updated to accept
undefined, which aligns with the broader type safety improvements in this PR.
35-39: LGTM!The explicit null check for
firstItemPayloadimproves type safety. While the early return at line 19 should prevent reaching this code with an empty array, the explicit check helps TypeScript narrow the type and adds defensive programming.src/state/selectors/combiners/combineCoordinateForDefaultIndex.ts (2)
9-9: LGTM!Parameter type updated to accept
undefined, aligning with the type safety improvements across combiners.
25-28: LGTM!Optional chaining correctly handles the case where
tooltipTicksis undefined. When ticks are unavailable, the function appropriately returnsundefinedafter the null check on line 26.src/util/getActiveCoordinate.ts (7)
19-19: LGTM!Parameter type updated to
number | undefined, correctly reflecting that active index may not be available.
51-51: LGTM!Consistent with the cartesian version - parameter type updated to handle undefined active index.
124-131: LGTM!Good defensive coding with optional chaining on tick coordinates and the guard clause to skip iterations where any coordinate is missing. This handles potential sparse arrays gracefully.
148-148: LGTM!Explicit tuple type annotation
[number, number]improves type clarity.
157-157: LGTM!Optional chaining on
unsortedTicks[i]?.indexsafely handles potential undefined elements.
164-164: LGTM!Consistent use of optional chaining.
170-195: LGTM!The refactored logic with early returns and null guards is cleaner and safer. The pattern of checking
prev != nullandnext != nullbefore comparisons prevents potential undefined arithmetic.src/state/selectors/selectors.ts (3)
77-85: Tightened return type forselectTooltipInteractionStatelooks correct.Annotating the selector to return
TooltipInteractionState(withoutundefined) aligns with usingcombineTooltipInteractionStateas the projector and simplifies callers likeselectActiveCoordinateandselectIsTooltipActive. No issues spotted here.
118-126: Non‑optional return fromselectTooltipPayloadConfigurationsis consistent with usage.Exposing
selectTooltipPayloadConfigurationsas always returningReadonlyArray<TooltipPayloadConfiguration>(rather than possiblyundefined) matches its role as input tocombineTooltipPayloadand avoids extra null checks at call sites. As long ascombineTooltipPayloadConfigurationsalready normalizes to an empty array, this is a safe and helpful tightening.
147-160: AllowingdefaultIndexCoordinateto beundefinedmatches selector input.Updating the projector signature in
selectActiveCoordinateto acceptdefaultIndexCoordinate: Coordinate | undefinedmatchesselectCoordinateForDefaultIndex’s declared return type and removes the previous mismatch. The fallback logictooltipInteractionState.coordinate ?? defaultIndexCoordinatestill behaves as intended.src/state/selectors/axisSelectors.ts (15)
94-102: Axis type aliases andselectBaseAxis/selectAxisSettingswiring look solid.Introducing
RenderableAxisSettings/AllAxisSettingsand routingselectBaseAxis/selectAxisSettingsthroughAllAxisTypes/RenderableAxisTypecentralizes axis handling nicely. The switches cover all members of the unions and throw on unexpected values, which is appropriate for internal invariants.Also applies to: 214-281
475-485: Error‑bar relevance and domain combining behave correctly underAllAxisTypes.
isErrorBarRelevantForAxisTypestill only treatsxAxisandyAxisas valid directions, and the updated uses incombineRelevantErrorBarSettingsandcombineDomainOfAllAppliedNumericalValuesIncludingErrorValuesensure that error bars are ignored for other axis types (z, angle, radius). That matches current feature scope and avoids accidental contributions from unsupported axes.Also applies to: 754-767, 782-789
626-687: Stack group accumulation and stack‑domain logic look correct.The updated
combineStackGroupsnow explicitly allocates an array when encountering a newstackId, which is clear and safe, and the resultingitemsGroupremains compatible with its declaredRecord<StackId, ReadonlyArray<DefinitelyStackedGraphicalItem>>.
combineDomainOfStackGroups’s newaxisTypegate forzAxis(earlyundefined) matches the comment that ZAxis ignores stacks, and skipping computation whendomainFromUserPreferenceis set keeps the latercombineNumericalDomainoptimization intact.
1008-1055: Numerical and overall axis‑domain composition underAllAxisTypeslooks correct.
combineNumericalDomainnow receivesaxisType: AllAxisTypesand uses it only to decide whether to includedomainOfStackGroups(horizontal/vertical layout with the “other” axis). That preserves existing semantics while allowing z/polar axes to skip stacks.
combineAxisDomainthen blends categorical/numerical behavior based onisCategoricalAxis(layout, axisType)and respectsstackOffsetType === 'expand'. The selectorsselectNumericalDomainandselectAxisDomainwire the pieces together consistently with the new axis‑type unions.Also applies to: 1094-1110
1112-1161:combineRealScaleTypeandselectRealScaleTypeintegration withAllAxisTypesis sound.Passing
axisType: AllAxisTypesintocombineRealScaleTypelets you handle radial layouts (radiusAxis→ band,angleAxis→ linear) while retaining the previous cartesian heuristics (e.g.,pointscale for certain line/area charts).selectRealScaleType’s signature matches the broader axis typing, and downstream consumers now see a consistent, stringly scale type.
1179-1200: Scale function and nice‑ticks computation handle categorical vs numerical domains safely.
combineScaleFunctionnow explicitly acceptsaxisDomain: NumberDomain | CategoricalDomain | undefinedandaxisRange: AxisRange | undefined, and it bails out when either is missing, which guards against incomplete selector wiring.
combineNiceTicks’s use ofRenderableAxisSettingsplusgetDomainDefinition(axisSettings)ensures tick generation respects both explicit domains and “auto” cases, and the checks aroundrealScaleType,axisSettings.type, andisWellFormedNumberDomainlook correct. TheselectNiceTicksselector wiring (usingRenderableAxisType) is consistent.Also applies to: 1203-1242
1244-1280: Nice‑tick domain extension correctly excludes angle axes.
combineAxisDomainWithNiceTicksnow takesaxisType: RenderableAxisTypeand explicitly excludes'angleAxis'from the “extend domain by nice ticks” path, matching the comment about existing angle‑axis behavior. For other numerical axes, extending the domain to include min/max nice ticks is done safely underisWellFormedNumberDomainand non‑emptyniceTicks.
1288-1361: Smallest‑distance and calculated padding logic are robust against edge cases.The updated
selectSmallestDistanceBetweenValuesimplementation now:
- Handles empty or singleton data by returning
Infinityand- Guards against
undefinedvalues in the sorted list.
selectCalculatedPaddingand itsselectCalculated{X,Y}AxisPadding/select{X,Y}AxisPaddingwrappers then treat non‑finite or missing distances as “no padding” (0), which is safe. Thegap/no-gaphandling viagetPercentValuematches the intended semantics while keeping all calculations inside the selector graph.Also applies to: 1363-1385
1490-1517: Axis range, reversed range, scale, and error‑bar selectors align with new axis types.
selectAxisRangeandselectAxisRangeWithReversenow acceptaxisType: AllAxisTypes, correctly delegating to cartesian, z, and polar helpers.selectAxisScale’s use ofRenderableAxisTypeensures only renderable axes feed intocombineScaleFunction, andselectErrorBarsSettingscontinues to limit error‑bar aggregation to cartesian items while keying offaxisType: AllAxisTypes.These changes look consistent with the new
AllAxisTypes/RenderableAxisTypetaxonomy.Also applies to: 1519-1536
1734-1760:selectCartesianAxisSizeis correctly constrained to cartesian axes.
selectCartesianAxisSizenow explicitly usesRenderableAxisTypeand only returns a size for'xAxis'and'yAxis', with a safeundefinedfallback for other axis types. That matches how cartesian axis sizes are used elsewhere and avoids accidental assumptions for polar/z axes.
1761-1787: Duplicate‑domain handling respects axis type and layout.
combineDuplicateDomainnow takesaxisType: AllAxisTypesand usesisCategoricalAxis(chartLayout, axisType)to decide when to surface duplicate domains. The selectorselectDuplicateDomainwiring is straightforward, and the behavior remains limited to axes where duplicates actually matter.
1789-1814: Categorical‑domain extraction for numeric/scaled axes is consistent.
combineCategoricalDomainandselectCategoricalDomainnow useRenderableAxisSettings/RenderableAxisTypeand only emit domains whenaxis.dataKeyis present and the layout+axisType combination is “categorical but numerically/scaled configured” (type'number'or non‑'auto'scale). This is in line with existing behavior and plays nicely with the broader axis typing.
1817-1869: Cartesian‑grid axis props selector matches new axis/scale/ticks plumbing.
selectAxisPropsNeededForCartesianGridTicksGeneratoris now parameterized byaxisType: 'xAxis' | 'yAxis'and pulls inrealScaleType,scale, duplicate/categorical domains, range, and nice ticks. The projector’s updatedrealScaleType: string | undefinedannotation matchescombineRealScaleType, and passingaxisTypethrough toisCategoricalAxiskeeps behavior consistent.
1871-1970: Axis and graphical‑item tick generation respect new renderable axis types.
combineAxisTicksandcombineGraphicalItemTicksboth:
- Guard on
axis,scale, andaxisRangepresence.- Use
isCategoricalAxis(layout, axisType)withRenderableAxisType.- Correctly handle user‑provided ticks/niceTicks, categorical domains, and numeric scale ticks (including duplicate domains).
The
offsethandling for band/angle axes remains consistent and the selectorsselectTicksOfAxis/selectTicksOfGraphicalItemare wired to the new axis/scale/domain selectors appropriately.Also applies to: 1972-2041
2045-2062: Axis‑with‑scale selectors align cartesian and z‑axis handling.
selectAxisWithScaleandselectZAxisWithScalenow encapsulate the pattern of pairing axis settings with a computedRechartsScale, returningundefinedwhen either side is missing. The type parameters (RenderableAxisTypefor the former, literal'zAxis'for the latter) make the intended usage explicit while keeping the implementation simple.Also applies to: 2064-2093
| export const selectTooltipAxis = (state: RechartsRootState): RenderableAxisSettings => { | ||
| const axisType = selectTooltipAxisType(state); | ||
| const axisId = selectTooltipAxisId(state); | ||
| return selectAxisSettings(state, axisType, axisId); | ||
| }; | ||
|
|
||
| export const selectTooltipAxisDataKey: (state: RechartsRootState) => DataKey<any> | undefined = createSelector( | ||
| [selectTooltipAxis], | ||
| (axis: AxisWithTicksSettings | undefined): DataKey<any> | undefined => axis?.dataKey, | ||
| (axis: RenderableAxisSettings | undefined): DataKey<any> | undefined => axis?.dataKey, | ||
| ); |
There was a problem hiding this comment.
🛠️ Refactor suggestion | 🟠 Major
Avoid DataKey<any> in selectTooltipAxisDataKey.
The selector itself is fine, but the exported type selectTooltipAxisDataKey: (state: RechartsRootState) => DataKey<any> | undefined violates the “no any” guideline. Since callers don’t get additional safety from any, you can switch to unknown without changing runtime behavior:
-export const selectTooltipAxisDataKey: (state: RechartsRootState) => DataKey<any> | undefined = createSelector(
+export const selectTooltipAxisDataKey: (state: RechartsRootState) => DataKey<unknown> | undefined = createSelector(
[selectTooltipAxis],
- (axis: RenderableAxisSettings | undefined): DataKey<any> | undefined => axis?.dataKey,
+ (axis: RenderableAxisSettings | undefined): DataKey<unknown> | undefined => axis?.dataKey,
);You may also want to align other DataKey<any> usages (e.g. in selectTooltipDataKey in selectors.ts) to DataKey<unknown> for consistency.
🤖 Prompt for AI Agents
In src/state/selectors/axisSelectors.ts around lines 593 to 602, the exported
selector type uses DataKey<any> which violates the no-any guideline; change the
selector's exported signature to return DataKey<unknown> | undefined (and update
any explicit type annotations on the createSelector export) so callers retain
the same runtime behavior but with safer typing; also scan and align
nearby/related selectors (e.g. selectTooltipDataKey in selectors.ts) to use
DataKey<unknown> for consistency.
There was a problem hiding this comment.
DataKey is one of those exceptions that are missing meaningful typing still. This one is pending a fix so we continue using any in foreseeable future.
There was a problem hiding this comment.
@PavelVanecek, thank you for clarifying! I've noted that DataKey<any> is an intentional exception to the typing guidelines while meaningful typing is being developed. I won't flag this pattern in future reviews.
✏️ Learnings added
Learnt from: PavelVanecek
Repo: recharts/recharts PR: 6750
File: src/state/selectors/axisSelectors.ts:593-602
Timestamp: 2025-12-08T08:23:26.219Z
Learning: In the recharts codebase, `DataKey<any>` is an intentional exception to the "no any" rule while proper typing is being developed. This should not be flagged in reviews.
Note: Learnings are effective only in the context of similar code segments. To apply general coding guidelines, please configure review instructions. You can manage existing learnings in the app.
🧠 Learnings used
Learnt from: PavelVanecek
Repo: recharts/recharts PR: 6669
File: www/src/docs/exampleComponents/ScatterChart/ScatterChartWithLabels.tsx:2-2
Timestamp: 2025-11-23T13:30:10.395Z
Learning: The `TooltipIndex` type from recharts is defined in `src/state/tooltipSlice.ts` but is not currently exported from the public API entry points. It should not be imported from `recharts/types/state/tooltipSlice` as this is an internal implementation path. An ESLint rule is needed to prevent regressions.
Learnt from: CR
Repo: recharts/recharts PR: 0
File: CONTRIBUTING.md:0-0
Timestamp: 2025-11-25T01:22:59.729Z
Learning: Applies to **/*.{ts,tsx} : Prefer `unknown` over `any` and refine the type in TypeScript
Learnt from: CR
Repo: recharts/recharts PR: 0
File: CONTRIBUTING.md:0-0
Timestamp: 2025-11-25T01:22:59.729Z
Learning: Applies to **/*.{ts,tsx} : Never use `any` type (implicit or explicit) in TypeScript code
Learnt from: CR
Repo: recharts/recharts PR: 0
File: CONTRIBUTING.md:0-0
Timestamp: 2025-11-25T01:22:59.729Z
Learning: Applies to **/*.{ts,tsx} : Type function parameters and return values explicitly in TypeScript, do not rely on implicit any or inference; exceptions are React components and trivial functions
Learnt from: CR
Repo: recharts/recharts PR: 0
File: DEVELOPING.md:0-0
Timestamp: 2025-12-06T03:36:59.377Z
Learning: Applies to **/*.{ts,tsx,js,jsx} : All imports from `recharts` must use the public API entry point; imports from internal paths like `recharts/types/*` or `recharts/src/*` are not allowed
Learnt from: PavelVanecek
Repo: recharts/recharts PR: 6659
File: www/src/components/GuideView/Performance/index.tsx:232-250
Timestamp: 2025-11-19T14:08:01.728Z
Learning: In Recharts version 3.4.2, object-as-prop optimizations were introduced to reduce unnecessary re-renders when new object references are passed as props. This affects the recommendation for the `react-perf/jsx-no-new-object-as-prop` ESLint rule.
| export const selectOrderedTooltipTicks = createSelector( | ||
| selectTooltipAxisTicks, | ||
| (ticks: ReadonlyArray<TickItem> | undefined) => sortBy(ticks, o => o.coordinate), | ||
| ); |
There was a problem hiding this comment.
Guard against undefined ticks in selectOrderedTooltipTicks.
selectTooltipAxisTicks can return ReadonlyArray<TickItem> | undefined, but the projector calls sortBy(ticks, ...) unconditionally. If ticks is undefined, this risks a runtime error and likely a TS error under strict settings.
You already propagate ReadonlyArray<TickItem> | undefined through combineActive* helpers, so it’s safe to return undefined when no ticks are present. Suggest:
-export const selectOrderedTooltipTicks = createSelector(
- selectTooltipAxisTicks,
- (ticks: ReadonlyArray<TickItem> | undefined) => sortBy(ticks, o => o.coordinate),
-);
+export const selectOrderedTooltipTicks = createSelector(
+ selectTooltipAxisTicks,
+ (
+ ticks: ReadonlyArray<TickItem> | undefined,
+ ): ReadonlyArray<TickItem> | undefined =>
+ ticks == null ? undefined : sortBy(ticks, o => o.coordinate),
+);📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| export const selectOrderedTooltipTicks = createSelector( | |
| selectTooltipAxisTicks, | |
| (ticks: ReadonlyArray<TickItem> | undefined) => sortBy(ticks, o => o.coordinate), | |
| ); | |
| export const selectOrderedTooltipTicks = createSelector( | |
| selectTooltipAxisTicks, | |
| ( | |
| ticks: ReadonlyArray<TickItem> | undefined, | |
| ): ReadonlyArray<TickItem> | undefined => | |
| ticks == null ? undefined : sortBy(ticks, o => o.coordinate), | |
| ); |
🤖 Prompt for AI Agents
In src/state/selectors/selectors.ts around lines 72 to 75, the selector
currently calls sortBy(ticks, ...) unconditionally which will throw if ticks is
undefined; change the projector to guard for undefined and return undefined in
that case (e.g., if ticks is falsy return undefined, otherwise return the sorted
array) so the selector's return type remains ReadonlyArray<TickItem> | undefined
and no runtime/TS errors occur.
| range: AxisRange | undefined, | ||
| ): number => { | ||
| let index = -1; | ||
| ): number | undefined => { |
There was a problem hiding this comment.
Return type includes undefined but function never returns undefined.
The return type is number | undefined, but the function only returns numbers (0, valid indices, or -1). Either the return type should be just number, or line 199 should return undefined instead of -1 to align with the declared return type.
Consider one of these options:
): number | undefined => {to
): number => {Or change line 199:
- return -1;
+ return undefined;📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| ): number | undefined => { | |
| ): number => { |
🤖 Prompt for AI Agents
In src/util/getActiveCoordinate.ts around line 113 (and referencing line 199),
the function signature declares a return type of number | undefined but the
implementation never returns undefined (it returns numeric values like 0 or -1);
update the code to make the types consistent by either changing the function
return type to just number, or modify the code at line 199 to return undefined
instead of -1 and update any callers or tests that expect -1 accordingly so the
runtime and type annotation match.
Codecov Report❌ Patch coverage is Additional details and impacted files@@ Coverage Diff @@
## main #6750 +/- ##
==========================================
- Coverage 93.90% 93.88% -0.03%
==========================================
Files 512 512
Lines 42462 42524 +62
Branches 4974 4991 +17
==========================================
+ Hits 39876 39923 +47
- Misses 2581 2596 +15
Partials 5 5 ☔ View full report in Codecov by Sentry. 🚀 New features to boost your workflow:
|
Bundle ReportChanges will increase total bundle size by 4.71kB (0.18%) ⬆️. This is within the configured threshold ✅ Detailed changes
Affected Assets, Files, and Routes:view changes for bundle: recharts/bundle-es6Assets Changed:
view changes for bundle: recharts/bundle-umdAssets Changed:
view changes for bundle: recharts/bundle-cjsAssets Changed:
|
|
Staging Deployment Details
These deployments will remain available for 30 days. To update snapshots: Comment |
|
these fixes help with readability a bit too which is nice |
Description
365 errors -> 269
Related Issue
#6645
Summary by CodeRabbit
Release Notes
New Features
Bug Fixes
Tests
✏️ Tip: You can customize this high-level summary in your review settings.