A writable derived store for objects and arrays with TypeScript support!
const user = writable({ name: { first: 'Rich', last: 'Harris' } })
const firstName = keyed(user, 'name.first')
$firstName = 'Bryan'
console.log($user) // { name: { first: 'Bryan', last: 'Harris' } };
npm i -D @humanspeak/svelte-keyed
Since Svelte automatically bundles all required dependencies, you only need to install this package as a dev dependency with the -D
flag.
keyed
takes a writable store and a keypath, and returns a writable store whose changes are reflected on the original store. The keypath can target nested properties in objects or elements in arrays.
Properties are accessed with dot notation, and arrays can be indexed with bracket notation:
const email = keyed(settings, 'profiles[0].email')
const firstItem = keyed(list, '[0]')
If the parent store is nullable, then the child store will also be nullable:
type User = {
name: {
first: string
last: string
}
relations: {
partner?: User
}
}
const maybeUser = writable<User | undefined>(undefined)
// Writable<string | undefined>
const firstName = keyed(maybeUser, 'name.first')
Properties are accessed with optional chaining behavior:
const user = writable(initUser)
// Writable<Name | undefined>
const partnerName = keyed(user, 'relations.partner.name')
The store supports array operations through bracket notation:
const list = writable(['a', 'b', 'c'])
const firstItem = keyed(list, '[0]')
const lastItem = keyed(list, '[-1]') // Access last element
keyed
provides full TypeScript support with type inference from the keypath:
const user = writable(initUser)
// Writable<string>
const firstName = keyed(user, 'name.first')
Type hints are provided for keypaths up to a depth of 3:
keyed(user, '...');
┌───────────────────────────────┐
│ • name │
│ • name.first │
│ • name.last │
│ • relations │
│ • relations.partner │
│ • relations.partner.name │
└───────────────────────────────┘
Note: The depth limit is due to TypeScript's requirement that structured types be generated statically. While deeper paths will work, they won't show in autocomplete.
Perfect for setting store properties in component context:
<!-- Settings.svelte -->
<script>
setContext('profileSettings', keyed(settings, 'profile'))
</script>
<GeneralSettings />
<ProfileSettings />
Ideal for passing store segments to Svelte actions:
<!-- Settings.svelte -->
<script>
const stats = writable({ userClicks: 0, userTaps: 0 })
const clicks = keyed(stats, 'userClicks')
</script>
<div use:trackClicks={clicks} />
Combine with other store operations for complex state management:
const settings = writable({ theme: 'light', fontSize: 16 })
const theme = keyed(settings, 'theme')
const isDarkMode = derived(theme, $theme => $theme === 'dark')