0.1.3 • Published 5 months ago
svelte-contextify v0.1.3
svelte-contextify
A tiny library for vastly improving context managament in Svelte apps by encapsulating the Context API.
Features
- Removes the need for keys
- Utilizes symbols to create unique keys
- Vastly improves type inference
Install
npm i svelte-contextify
pnpm add svelte-contextify
yarn add svelte-contextify
bun add svelte-contextify
The problem
// session.ts
export type Session = {
user: string;
};
// session.ts
export type Session = {
user: string;
};
<!-- Parent.svelte -->
<script lang="ts">
import { setContext } from 'svelte';
import type { Session } from '$lib/session.ts';
setContext<Session>('session', { user: 'Hugos68' });
</script>
<!-- Child.svelte -->
<script lang="ts">
import { getContext } from 'svelte';
import type { Session } from '$lib/session.ts';
const session = getContext<Session>('session');
</script>
The snippet above show a fairly common use case, we want to store session in context (so it is SSR safe) and pass it down to a child so it can access it safely. This has 2 problems/annoyances:
- We need to keep track of the context key (
session
) in 2 different places. - We need to keep track of the type in 2 different places.
How svelte-contextify fixes the problem
import { getContext, setContext } from 'svelte';
export function createContext<T>(): [() => T | undefined, (value: T) => T, symbol];
export function createContext<T>(fallback: T): [() => T, (value: T) => T, symbol];
export function createContext<T>(fallback?: T) {
const key = Symbol();
return [() => getContext<T>(key) ?? fallback, (value: T) => setContext<T>(key, value), key];
}
Pretty simple right?
We return 3 things here:
- The get function: This is responsible for retrieving the value out of context
- The set function: This is responsible for setting the value in context
- The generated key: This is a unique symbol that is returned in case you need to use it outside of the supplied get or set functions
This allows you to turn the code snippet above into:
// session.ts
type Session = {
user: string;
};
export const [getSession, setSession, key] = createContext<Session>();
<!-- Parent.svelte -->
<script lang="ts">
import { setSession } from './session.ts';
setSession({ user: 'Hugos68' }); // Full type safety when setting the session
</script>
<!-- Child.svelte -->
<script lang="ts">
import { getSession } from './session.ts';
const session = getSession(); // type Session is inferred
</script>
This improves the experience in 2 main ways:
- No need to specify a key anymore (or keep track of)
- The type only needs to be specified once and is applied to both the getter and setter implicitly