Package Exports
- svelte-keyed
- svelte-keyed/dist/index.es.js
- svelte-keyed/dist/index.js
This package does not declare an exports field, so the exports above have been automatically detected and optimized by JSPM instead. If any package subpath is missing, it is recommended to post an issue to the original package (svelte-keyed) to support the "exports" field. If that is not possible, create a JSPM override to customize the exports field for this package.
Readme
svelte-keyed
A writable derived store for objects and arrays!
const user = writable({ name: { first: 'Rich', last: 'Harris' } });
const firstName = keyed(user, 'name.first');
$firstName = 'Bryan';
console.log($user); // { name: { first: 'Bryan', last: 'Harris' } };
Installation
$ npm i -D svelte-keyed
Since Svelte automatically bundles all required dependencies, you only need to install this package as a dev dependency with the -D
flag.
API
keyed
takes a writable object store and a keypath, and returns a writable store whose changes are reflected on the original store.
Properties are accessed with dot notation, and arrays can be indexed with bracket notation.
const email = keyed(settings, 'profiles[0].email');
Nullable parents
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');
Nullable properties
Nullable properties are accessed with optional chaining behaviour.
const user = writable(initUser);
// Writable<Name | undefined>
const partnerName = keyed(user, 'relations.partner.name');
TypeScript
keyed
infers the return type of the keyed store from the keypath.
const user = writable(initUser);
// Writable<string>
const firstName = keyed(user, 'name.first');
keyed
will also try to guess all possible keypaths up to a depth limit of 3.
keyed(user, '...');
┌───────────────────────────────┐
│ • name │
│ • name.first │
│ • name.last │
│ • name │
│ • relations │
│ • relations.partner │
│ • relations.partner.name │
└───────────────────────────────┘
This limit is due to a TypeScript limitation where structured types must be generated statically. Increasing the depth limit slows down type compilation.
Type hints will not be provided for keypaths with a depth greater than 3 but this does not affect the return type.
const user = writable(user);
// Writable<string | undefined>
const firstName = keyed(user, 'relations.partner.name.first');
Motivations
We usually read and write properties of an object store with auto-subscriptions.
<input bind:value={$name.first}/>
However, auto-subscriptions are isolated to a Svelte component. svelte-keyed
aims to solve several common limitations listed below.
Context stores
Often, we want to set a property or element of a store into component context, then allow child components to read / write to the property.
<!-- Settings.svelte -->
<script>
setContext('profileSettings', keyed(settings, 'profile'));
</script>
<GeneralSettings />
<ProfileSettings />
<!-- ProfileSettings.svelte -->
<script>
const profileSettings = getContext('profileSettings');
</script>
<input type="text" bind:value={$profileSettings.username} />
Helper functions
One important method to reduce clutter on your component is to extract functionality into external helper functions. svelte-keyed
allows you to create derived Writable
stores that can be passed into or returned from helper functions.
<!-- Settings.svelte -->
<script>
const stats = writable({ userClicks: 0, userTaps: 0 });
const clicks = keyed(stats, 'userClicks');
</script>
<div use:trackClicks={clicks} />
<input use:trackClicks={clicks} />
export const trackClicks = (node, clicks) => {
const listen = () => {
clicks.update(($clicks) => $clicks + 1);
};
node.addEventListener('click', listen);
return {
destroy() {
node.removeEventListener('click', listen);
},
};
};