Skip to content

Instantly share code, notes, and snippets.

@joshwashywash
Last active November 6, 2023 16:21
Show Gist options
  • Save joshwashywash/a0b840f3c204a21ade3cf88cc78a2630 to your computer and use it in GitHub Desktop.
Save joshwashywash/a0b840f3c204a21ade3cf88cc78a2630 to your computer and use it in GitHub Desktop.
typesafe contexts in svelte (maybe typos but you get the idea...)
// contexts/index.ts
import { getContext, hasContext, setContext } from 'svelte';

export const create = <Context>(identifier: string) => {
	const key = Symbol();
	return {
		set(context: Context) {
			return setContext<Context>(key, context);
		},
		get() {
			if (hasContext(key)) {
				return getContext<Context>(key);
			}
			throw new Error(`${identifier} context was never set`);
		}
	};
};

usage:

// contexts/theme/types.ts
import type { Writable } from 'svelte/store';

export type Theme = 'light' | 'dark';

export type ThemeContext = Writable<Theme>;
// contexts/theme/index.ts
import type { ThemeContext } from '$lib/contexts/theme/types.ts';
import type { Writable } from 'svelte/store';
import { create } from '$lib/contexts';

export const { get, set } = create<ThemeContext>('theme');
<!-- components/Theme.svelte -->
<script lang="ts">
	import type { Theme } from '$lib/contexts/theme/types';
	import { set } from '$lib/contexts/theme';
	import { writable } from 'svelte/store';
	
	const theme = writable<Theme>('light');
	set(theme);
	
	const toDark = () => { theme.set('dark'); };
<script>

<button type="button" on:click={toDark}>dark</button>
<!-- components/P.svelte -->
<script lang="ts">
	import { get } from '$lib/contexts/theme';
	
	const theme = get();
</script>

<p>{$theme}</p>
<!-- +page.svelte -->
<script lang="ts">
import P from '$lib/components/P.svelte';
import Theme from '$lib/components/Theme.svelte';

<Theme />
<P />
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment