fix(table-core): preserve undefined in DeepValue for optional deep accessor keys#6444
Conversation
When a deep string accessor key traverses an optional (or nullable) parent key, `DeepValue` dropped the `undefined` from the resolved value type. This made `getValue()` for a path like `user.salary.amount` typed as `number` even when `salary` is optional, hiding a possible `undefined` that the runtime accessor (which uses optional chaining) can return. Distribute over the leaf union and map `null`/`undefined` members to `undefined`, matching the optional-chaining semantics of the deep accessor function.
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (3)
📝 WalkthroughWalkthroughUpdates ChangesOptional Deep Accessor Types
Estimated code review effort: 2 (Simple) | ~10 minutes Possibly related PRs
Suggested reviewers: 🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✨ 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 |
|
View your CI Pipeline Execution ↗ for commit 355e2bd
☁️ Nx Cloud last updated this comment at |
🎯 Changes
Fixes the
DeepValuetype so that a deep string accessor key that traverses an optional (or nullable) parent key keepsundefinedin the resolved value type.🔎 Root cause
DeepValuerecurses down the dotted key path. When a parent key is optional, the branch value is a union such as{ amount: number } | undefined. The conditional distributes over that union, and theundefinedmember falls through to the final: never, so theundefinedwas silently dropped from the leaf type.The runtime deep accessor built in
constructColumnwalks the path with optional chaining (result?.[key]), so a missing/null/undefinedintermediate value actually resolves toundefinedat runtime. The type therefore under-reported the possible values.🛠️ The fix
Add a leading
T extends null | undefined ? undefinedguard toDeepValue. Because the conditional distributes over the leaf union,undefined/nullintermediates now contributeundefined(matching the optional-chaining behavior of the runtime accessor), while every existing non-nullish path is unchanged.✅ How this was checked
Added a regression test in
tests/unit/helpers/columnHelper.test.tsalongside the existing accessor type tests. It asserts, viaexpectTypeOf, thatinfo.getValue()isnumber | undefinedfor the optional deep pathuser.salary.amount, and confirms the value still resolves at runtime. This is exercised bytest:types(tsc) andtest:lib(vitest); non-optional and numeric/tuple accessor paths keep their existing types.Note: this targets the v9
betabranch. The equivalent v8 report is #6238 (the v8 code lives in a different file,src/utils.ts).🚀 Release Impact
Summary by CodeRabbit
undefinedwhen intermediate data may be missing.