-
Notifications
You must be signed in to change notification settings - Fork 904
fix(components): improve slots return types #5237
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. Weβll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: v4
Are you sure you want to change the base?
Conversation
@benjamincanac could I ask you to double check the various |
commit: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Additional Comments:
src/runtime/components/Avatar.vue (line 33):
The AvatarSlots
interface was not updated to use the new typing pattern and still returns any
.
View Details
π Patch Details
diff --git a/src/runtime/components/Avatar.vue b/src/runtime/components/Avatar.vue
index 8d4b1211..be51d419 100644
--- a/src/runtime/components/Avatar.vue
+++ b/src/runtime/components/Avatar.vue
@@ -3,6 +3,7 @@ import type { AppConfig } from '@nuxt/schema'
import theme from '#build/ui/avatar'
import type { ChipProps, IconProps } from '../types'
import type { ComponentConfig } from '../types/tv'
+import type { SlotsReturn } from '../types/utils'
type Avatar = ComponentConfig<typeof theme, AppConfig, 'avatar'>
@@ -30,7 +31,7 @@ export interface AvatarProps {
}
export interface AvatarSlots {
- default(props?: {}): any
+ default?(props?: {}): SlotsReturn
}
</script>
Analysis
Inconsistent typing pattern in Avatar.vue AvatarSlots interface
What fails: AvatarSlots interface in Avatar.vue uses outdated typing pattern default(props?: {}): any
instead of the consistent default?(props?: {}): SlotsReturn
pattern used across all other components
How to reproduce:
grep -r "default(props?: {}): any" src/runtime/components/ # Shows only Avatar.vue
grep -r "default?(props?: {}): SlotsReturn" src/runtime/components/ # Shows 31+ other components
Result: Avatar.vue is the only component not following the new typing standard, missing SlotsReturn import and optional slot syntax
Expected: Avatar.vue should follow the same consistent pattern as all other components: optional slots with ?
and SlotsReturn
return type, as defined in src/runtime/types/utils.ts
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Additional Comments:
src/runtime/components/prose/CodeGroup.vue (lines 57-60):
The null/undefined handling for slot returns is incorrect and will cause runtime errors when no default slot is provided.
View Details
π Patch Details
diff --git a/src/runtime/components/prose/CodeGroup.vue b/src/runtime/components/prose/CodeGroup.vue
index f891963e..9a8c203c 100644
--- a/src/runtime/components/prose/CodeGroup.vue
+++ b/src/runtime/components/prose/CodeGroup.vue
@@ -56,7 +56,7 @@ const items = computed<{
rerenderCount.value
let children = slots.default?.()
if (!Array.isArray(children)) {
- children = [children]
+ children = children ? [children] : []
}
return children?.flatMap(transformSlot).filter(Boolean) || []
})
Analysis
Runtime error in CodeGroup.vue when slots.default() returns null/undefined
What fails: transformSlot()
function in src/runtime/components/prose/CodeGroup.vue
throws TypeError when accessing slot.type
on null/undefined values from empty slots
How to reproduce:
// When slots.default?.() returns null/undefined, current code wraps as [null]/[undefined]
let children = null; // or undefined
if (!Array.isArray(children)) {
children = [children]; // Creates [null] or [undefined]
}
children.flatMap(transformSlot); // Throws: "Cannot read properties of null (reading 'type')"
Result: TypeError: Cannot read properties of null/undefined (reading 'type') in transformSlot function
Expected: Should handle empty slots gracefully without runtime errors, returning empty array like AvatarGroup.vue pattern
Documentation: Vue 3 slots can return null/undefined in certain scenarios - components should handle these cases defensively per Vue 3 slot handling patterns
src/runtime/components/prose/CodeTree.vue (lines 68-71):
The null/undefined handling for slot returns is incorrect and will cause runtime errors when no default slot is provided.
View Details
π Patch Details
diff --git a/src/runtime/components/prose/CodeTree.vue b/src/runtime/components/prose/CodeTree.vue
index fc4d3cee..20281270 100644
--- a/src/runtime/components/prose/CodeTree.vue
+++ b/src/runtime/components/prose/CodeTree.vue
@@ -67,7 +67,7 @@ const flatItems = computed<{
rerenderCount.value
let children = slots.default?.()
if (!Array.isArray(children)) {
- children = [children]
+ children = children ? [children] : []
}
return children?.flatMap(transformSlot).filter(Boolean) || []
})
Analysis
Runtime error in CodeTree.vue when no default slot is provided
What fails: flatItems
computed in CodeTree.vue throws "Cannot read properties of undefined (reading 'type')" when component has no default slot content
How to reproduce:
<CodeTree /> <!-- No slot content provided -->
Result: Runtime error occurs in transformSlot()
function when it tries to access slot.type
on undefined
value
Expected: Component should render empty tree without errors, similar to AvatarGroup.vue behavior
The issue occurs because slots.default?.()
returns undefined
when no slot is provided, but the code wraps it as [undefined]
instead of []
, causing transformSlot
to receive undefined
values.
Fix: Updated the null handling to match the AvatarGroup.vue pattern that correctly handles this case.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Additional Comments:
src/runtime/components/prose/Accordion.vue (lines 49-50):
Inconsistent handling of undefined slot returns compared to other prose components, causing unnecessary processing of undefined values.
View Details
π Patch Details
diff --git a/src/runtime/components/prose/Accordion.vue b/src/runtime/components/prose/Accordion.vue
index fb9ac96e..22f5fa82 100644
--- a/src/runtime/components/prose/Accordion.vue
+++ b/src/runtime/components/prose/Accordion.vue
@@ -47,7 +47,7 @@ const items = computed<{
rerenderCount.value
let children = slots.default?.()
if (!Array.isArray(children)) {
- children = [children]
+ children = children ? [children] : []
}
return children?.flatMap(transformSlot).filter(Boolean) || []
})
diff --git a/src/runtime/components/prose/Tabs.vue b/src/runtime/components/prose/Tabs.vue
index 1438d950..c85a4d2c 100644
--- a/src/runtime/components/prose/Tabs.vue
+++ b/src/runtime/components/prose/Tabs.vue
@@ -61,7 +61,7 @@ const items = computed<{
rerenderCount.value
let children = slots.default?.()
if (!Array.isArray(children)) {
- children = [children]
+ children = children ? [children] : []
}
return children?.flatMap(transformSlot).filter(Boolean) || []
})
Analysis
Inconsistent undefined handling in slot processing causes unnecessary function calls
What fails: Accordion.vue and Tabs.vue use children = [children]
when processing slot returns, creating [undefined]
when slots.default?.()
returns undefined, leading to unnecessary transformSlot(undefined)
calls.
How to reproduce:
// When slots.default?.() returns undefined:
// Current approach calls transformSlot(undefined)
// Optimized approach skips processing entirely
Result: Current approach: { result: [], transformCalls: 1 }
, Optimized approach: { result: [], transformCalls: 0 }
Expected: Consistent with CodeGroup.vue and CodeTree.vue pattern: children = children ? [children] : []
to avoid processing undefined values and reduce unnecessary function calls.
Pattern confirmed in codebase: CodeGroup.vue and CodeTree.vue already implement this optimization correctly.
@sandros94 Should we also update all |
To provide typing? Shouldn't |
It doesn't work on my end, but if you say |
When writing in tsx with |
Yes but only when importing from |
π Linked issue
Resolves #5232
β Type of change
π Description
Until the last update for the builder we weren't able to properly and strongly type various aspects about props, slots and emits. Now the issue has been fixed by slots were left unchanged (all being required and return was
any
). With this change normal use in the template won't change, but does greatly increase the typing experience when using render functions (required for the current UTable implementation).π Checklist