Svelte helper utilities, types, and components for building type-safe Svelte 5 applications.
bun add @atom-forge/svelte-helpers
Standard type for components that accept external CSS classes.
let { class: classes }: ClassProp = $props();
const cls = $derived(twMerge('base-styles', classes));
For extra HTML attributes to be spread onto elements (...props). Always place at the end of the intersection.
let { class: classes, ...props }: ClassProp & AnyProp = $props();
// ...
<input {...props} class={cls} />
Consistent naming for snippet props.
// Required children snippet
let { children }: ChildrenProp = $props();
// Optional children snippet
let { children }: ChildrenPropOptional = $props();
// Parameterized snippet
let { children }: ChildrenProp<[Item]> = $props();
Enforce mutually exclusive props instead of string unions for better type safety.
// small OR compact, but not both
type Props = XOR<{ small: true }, { compact: true }, {}>;
// 3+ exclusive variants
type ButtonProps = XOR<{ primary: true }, { secondary: true }, { ghost: true }, {}>;
Ensures that at least one of the properties in an object is provided.
type LabelOrIcon = AtLeastOne<{ label: string; icon: IconDefinition }>;
Boolean props are simpler in templates; variantMap returns the string value for internal logic. Works best when combined with XOR or AtLeastOne prop types.
const { small, compact, ...props } = $props();
const size = untrack(() => variantMap({ small, compact }, 'normal'));
// Returns 'small' | 'compact' | 'normal'
Standard utilities to limit function execution rate.
const handleInput = debounce((val) => {
console.log(val);
}, 300);
const search = debounceAsync(async (query) => {
return await api.fetch(query);
}, 500);
TypeCast helper for Svelte templates and snippets. The TypeScript as keyword is not allowed inside Svelte template expressions — use this helper to restore type safety inline.
Primitive shorthands — for inline use in templates:
{@const on = as.boolean(td[k])}
{@const label = as.string(item.value)}
{@render list(as.array<string>(items))}
Available shorthands: as.string, as.number, as.boolean, as.array, as.object, as.function, as.any, as.unknown.
Generic usage — for custom interfaces inline:
const user = as<{ name: string; age: number }>(userData);
Script-side casters — recommended for complex or frequently reused types:
import { as } from '@atom-forge/svelte-helpers';
const toTask = as<{ title: string; done: boolean }>;
const toKey = as<keyof TableData>;
{@const task = toTask(_task)}
{@const on = as.boolean(td[toKey(k)])}
Snippet parameter typing — use a script-side caster instead of inline type annotations in snippet params:
<script lang="ts">
import { as } from '@atom-forge/svelte-helpers';
const itemArgType = as<{ title: string }>;
</script>
{#snippet item(_task)}
{@const task = itemArgType(_task)}
{task.title}
{/snippet}
A helper component to safely render snippets dynamically. Especially useful when an API expects a Component — you can pass RenderSnippet wrapping your snippet.
<RenderSnippet {snippet} args={{ item, index }} />