refactor: remove type assertions in component props

- create proper UncapStarProps and TranscendenceStarProps interfaces
- use discriminated union for StarRender type
- add function overloads for createStarProps with type safety
- remove 'as any' casts from star component spreading
- remove optionalProps workaround in SegmentedControl
- stop spreading HTMLAttributes to RadioGroupPrimitive (not supported)
This commit is contained in:
Justin Edmund 2025-11-28 21:40:08 -08:00
parent 654eabbeba
commit ca16ca145b
2 changed files with 50 additions and 16 deletions

View file

@ -7,7 +7,6 @@
import type { Snippet } from 'svelte'
import styles from './segmented-control.module.scss'
import type { HTMLAttributes } from 'svelte/elements'
import { optionalProps } from '$lib/utils/typeShims'
export type SegmentedControlVariant = 'default' | 'blended' | 'background'
@ -32,8 +31,7 @@
gap = false,
class: className,
wrapperClass,
children,
...restProps
children
}: Props = $props()
// Provide variant to child segments via context
@ -85,7 +83,7 @@
</script>
<div class={wrapperClassList}>
<RadioGroupPrimitive.Root bind:value class={classList} {...(optionalProps(restProps) as any)}>
<RadioGroupPrimitive.Root bind:value class={classList}>
{@render children?.()}
</RadioGroupPrimitive.Root>
</div>

View file

@ -19,15 +19,34 @@
updateTranscendence?: ((index: number) => void) | undefined
}
interface StarRender {
type: 'uncap' | 'transcendence'
props: {
index?: number
onStarClick?: (index: number, empty: boolean) => void
[key: string]: any
}
// Props for UncapStar component
interface UncapStarProps {
empty?: boolean
special?: boolean
flb?: boolean
ulb?: boolean
index: number
tabindex?: number
onStarClick: (index: number, empty: boolean) => void
}
// Props for TranscendenceStar component
interface TranscendenceStarProps {
className?: string
stage?: number
type?: 'character' | 'weapon' | 'summon'
editable?: boolean
interactive?: boolean
tabindex?: number
onStarClick?: () => void
onFragmentClick?: (newStage: number) => void
onFragmentHover?: (newStage: number) => void
}
type StarRender =
| { type: 'uncap'; props: UncapStarProps }
| { type: 'transcendence'; props: TranscendenceStarProps }
let {
type,
rarity,
@ -77,13 +96,26 @@
}
}
// Options for creating uncap star props
interface UncapStarOptions {
index: number
flb?: boolean
ulb?: boolean
special?: boolean
}
// Helper function to create star props
const createStarProps = (starType: 'uncap' | 'transcendence', options: any = {}): StarRender => {
function createStarProps(starType: 'transcendence'): StarRender
function createStarProps(starType: 'uncap', options: UncapStarOptions): StarRender
function createStarProps(
starType: 'uncap' | 'transcendence',
options?: UncapStarOptions
): StarRender {
if (starType === 'transcendence') {
return {
type: 'transcendence',
props: {
stage: transcendenceStage,
stage: transcendenceStage ?? 0,
type,
editable,
interactive: editable,
@ -92,6 +124,10 @@
}
}
if (!options) {
throw new Error('Options required for uncap star')
}
return {
type: 'uncap',
props: {
@ -100,7 +136,7 @@
flb: options.flb,
ulb: options.ulb,
special: options.special,
tabIndex: editable ? 0 : undefined,
tabindex: editable ? 0 : undefined,
onStarClick: editable ? toggleStar : () => {}
}
}
@ -164,9 +200,9 @@
{@const star = renderStar(i)}
{#if star}
{#if star.type === 'transcendence'}
<TranscendenceStar {...(star.props as any)} />
<TranscendenceStar {...star.props} />
{:else}
<UncapStar {...(star.props as any)} />
<UncapStar {...star.props} />
{/if}
{/if}
{/each}