Improved type safety in edit recommendation modal#26124
Improved type safety in edit recommendation modal#26124PedroMarianoAlmeida wants to merge 3 commits intoTryGhost:mainfrom
Conversation
📝 WalkthroughWalkthroughA type guard and wrapper function were added to the recommendation edit modal to distinguish between complete and partial recommendation objects, enforcing that edit operations work with fully-formed Recommendation instances while supporting the more flexible EditOrAddRecommendation type. Changes
Poem
🚥 Pre-merge checks | ✅ 3✅ Passed checks (3 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ 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: 1
🤖 Fix all issues with AI agents
In
`@apps/admin-x-settings/src/components/settings/growth/recommendations/edit-recommendation-modal.tsx`:
- Around line 14-16: The type guard isRecommendation should not only check
property presence but also validate runtime types: update the function
isRecommendation to verify typeof value.created_at === 'string', typeof value.id
=== 'string', and that value.updated_at is either null or a string (i.e.
value.updated_at === null || typeof value.updated_at === 'string'); keep the
existing property checks but replace them with these explicit typeof/null checks
to ensure robust discrimination between EditOrAddRecommendation and
Recommendation.
| const isRecommendation = (value: EditOrAddRecommendation | Recommendation): value is Recommendation => { | ||
| return 'created_at' in value && 'updated_at' in value && typeof value.id === 'string'; | ||
| }; |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
rg -n "export type Recommendation" -A15 apps/admin-x-framework/src/api/recommendations.tsRepository: TryGhost/Ghost
Length of output: 645
🏁 Script executed:
# Also check the EditOrAddRecommendation type
rg -n "export type EditOrAddRecommendation" -A15 apps/admin-x-framework/src/api/recommendations.tsRepository: TryGhost/Ghost
Length of output: 732
🏁 Script executed:
# Check how isRecommendation is actually used in the file
rg -n "isRecommendation" -B2 -A2 apps/admin-x-settings/src/components/settings/growth/recommendations/edit-recommendation-modal.tsxRepository: TryGhost/Ghost
Length of output: 614
🏁 Script executed:
# Check for other type guards in the same file for comparison
rg -n "is.*=.*value is" apps/admin-x-settings/src/components/settings/growth/recommendations/edit-recommendation-modal.tsx -B2 -A5Repository: TryGhost/Ghost
Length of output: 439
🏁 Script executed:
# Look for similar type guard patterns across the admin-x-settings codebase
rg "value is.*=>.*typeof.*in" apps/admin-x-settings -B1 -A3 --max-count=5Repository: TryGhost/Ghost
Length of output: 40
🏁 Script executed:
# Check if EditOrAddRecommendation can actually be passed to isRecommendation in practice
rg -n "EditOrAddRecommendation" apps/admin-x-settings/src/components/settings/growth/recommendations/edit-recommendation-modal.tsx -B3 -A3Repository: TryGhost/Ghost
Length of output: 883
Strengthen type validation in isRecommendation guard.
The type guard correctly distinguishes between EditOrAddRecommendation and Recommendation by checking for created_at and updated_at properties, but it only verifies their presence, not their types. Since created_at must be a string and updated_at can be string or null (per the Recommendation type), consider validating these types explicitly for runtime robustness.
Suggested enhancement
const isRecommendation = (value: EditOrAddRecommendation | Recommendation): value is Recommendation => {
- return 'created_at' in value && 'updated_at' in value && typeof value.id === 'string';
+ return typeof value === 'object'
+ && value !== null
+ && 'created_at' in value
+ && typeof value.created_at === 'string'
+ && 'updated_at' in value
+ && (typeof value.updated_at === 'string' || value.updated_at === null)
+ && typeof value.id === 'string';
};🤖 Prompt for AI Agents
In
`@apps/admin-x-settings/src/components/settings/growth/recommendations/edit-recommendation-modal.tsx`
around lines 14 - 16, The type guard isRecommendation should not only check
property presence but also validate runtime types: update the function
isRecommendation to verify typeof value.created_at === 'string', typeof value.id
=== 'string', and that value.updated_at is either null or a string (i.e.
value.updated_at === null || typeof value.updated_at === 'string'); keep the
existing property checks but replace them with these explicit typeof/null checks
to ensure robust discrimination between EditOrAddRecommendation and
Recommendation.
|
Should I do what the robot suggests? |
This PR is a small code quality improvement without an associated
issue.
What does it do?
Removes an unsafe
as anytype cast from the edit recommendation modaland replaces it with:
isRecommendation) with proper type predicateupdateFormprop usingReact.ComponentPropsWhy?
I enjoy improving TypeScript type safety in open source projects as a
hobby. I've been doing similar work in other projects (like
react-bits and paypal-js#640), and
wanted to contribute the same improvements to Ghost.
Type casts with
anybypass TypeScript's safety and can mask runtimeerrors. This change makes the code fully type-checked while maintaining
identical behavior.
Impact
bugs at compile-time
Checklist
/TryGhost/Ghost/blob/main/.github/CONTRIBUTING.md)
compilation validates the types. No new tests needed as this is a type
safety improvement with no behavioral changes.
Note
Low Risk
Type-safety refactor limited to the edit recommendation modal; behavior should be unchanged aside from a new explicit runtime error if an unexpected partial recommendation shape is returned.
Overview
Removes an unsafe
as anycast when passingupdateFormintoRecommendationDescriptionForminedit-recommendation-modal.tsx.Adds an
isRecommendationtype guard and a typedupdateFormForComponentwrapper (derived viaReact.ComponentProps) that enforces the edit modal always returns a fullRecommendationshape, throwing a clear error if not.Written by Cursor Bugbot for commit 9fa3449. This will update automatically on new commits. Configure here.
Summary by CodeRabbit