Accessors
The goal of the accessor APIs is simple: safely work with deeply nested data without manually checking every intermediate level.
Interactive demo
Use this playground to edit JSON, the pattern, and write values directly while observing the result of getIn, existIn, setIn, deleteIn, and ensureIn.
<script setup lang="ts">
import { Path } from '@silver-formily/path'
import { computed, ref } from 'vue'
const initialSource = {
user: {
profile: {
nickname: 'silver',
city: 'Shanghai',
},
},
list: [{ label: 'first' }],
}
const sourceText = ref(JSON.stringify(initialSource, null, 2))
const pattern = ref('user.profile.nickname')
const setValueText = ref('"new-name"')
const defaultValueText = ref('"guest"')
const parsedSource = computed(() => {
try {
return { value: JSON.parse(sourceText.value), error: '' }
}
catch (error) {
return { value: null, error: error instanceof Error ? error.message : String(error) }
}
})
const readState = computed(() => {
if (parsedSource.value.error || !parsedSource.value.value) {
return { getValue: '-', exists: false, error: parsedSource.value.error }
}
try {
const source = parsedSource.value.value
return {
getValue: JSON.stringify(Path.getIn(source, pattern.value), null, 2) ?? 'undefined',
exists: Path.existIn(source, pattern.value),
error: '',
}
}
catch (error) {
return {
getValue: '-',
exists: false,
error: error instanceof Error ? error.message : String(error),
}
}
})
function parseLooseValue(input: string) {
try {
return JSON.parse(input)
}
catch {
return input
}
}
function applyMutation(type: 'set' | 'ensure' | 'delete') {
if (parsedSource.value.error || !parsedSource.value.value)
return
const next = JSON.parse(JSON.stringify(parsedSource.value.value))
if (type === 'set') {
Path.setIn(next, pattern.value, parseLooseValue(setValueText.value))
}
else if (type === 'ensure') {
Path.ensureIn(next, pattern.value, parseLooseValue(defaultValueText.value))
}
else {
Path.deleteIn(next, pattern.value)
}
sourceText.value = JSON.stringify(next, null, 2)
}
function reset() {
sourceText.value = JSON.stringify(initialSource, null, 2)
pattern.value = 'user.profile.nickname'
setValueText.value = '"new-name"'
defaultValueText.value = '"guest"'
}
</script>
<template>
<div class="playground">
<div class="grid">
<label class="field">
<span class="fieldLabel">Pattern</span>
<input v-model="pattern" class="input">
</label>
<label class="field">
<span class="fieldLabel">setIn value</span>
<input v-model="setValueText" class="input">
</label>
<label class="field">
<span class="fieldLabel">ensureIn default</span>
<input v-model="defaultValueText" class="input">
</label>
</div>
<label class="field">
<span class="fieldLabel">Source JSON</span>
<textarea v-model="sourceText" class="textarea" spellcheck="false" />
</label>
<div class="toolbar">
<button class="btn" @click="applyMutation('set')">
apply setIn
</button>
<button class="btn" @click="applyMutation('ensure')">
apply ensureIn
</button>
<button class="btn secondary" @click="applyMutation('delete')">
apply deleteIn
</button>
<button class="btn secondary" @click="reset">
reset
</button>
</div>
<div v-if="parsedSource.error || readState.error" class="errorBox">
{{ parsedSource.error || readState.error }}
</div>
<div class="panelGrid">
<div class="panel">
<div class="panelTitle">
getIn result
</div>
<div class="panelBody metricValue">
{{ readState.getValue }}
</div>
</div>
<div class="panel">
<div class="panelTitle">
existIn result
</div>
<div class="panelBody">
<span :class="readState.exists ? 'statusTrue' : 'statusFalse'">
{{ readState.exists }}
</span>
</div>
</div>
</div>
</div>
</template>
<style scoped src="../../shared/path-demo.css"></style>getIn
const values = {
user: {
profile: {
nickname: 'silver',
},
},
}
Path.getIn(values, 'user.profile.nickname')
// 'silver'
Path.getIn(values, 'user.profile.missing')
// undefinedIf you already have a Path instance, the instance method is equally natural:
const profileName = Path.parse('user.profile.nickname')
profileName.getIn(values)
// 'silver'setIn
setIn creates missing intermediate layers when needed:
const values = {}
Path.setIn(values, 'user.profile.nickname', 'silver')
// {
// user: {
// profile: {
// nickname: 'silver'
// }
// }
// }If the next segment is numeric, it creates an array:
const values = {}
Path.setIn(values, 'users.0.name', 'silver')
// { users: [{ name: 'silver' }] }The instance form works the same way:
const profileName = Path.parse('user.profile.nickname')
const values = {}
profileName.setIn(values, 'silver')
profileName.getIn(values)
// 'silver'existIn
existIn checks whether the property really exists, not whether its value is truthy:
Path.existIn({ a: { b: { c: 0 } } }, 'a.b.c')
// true
Path.existIn({ a: { b: {} } }, 'a.b.c')
// falseIt also accepts an offset path for base-aware checks:
Path.existIn({ a: [{}] }, 'b.a.0', Path.parse('b'))
// trueIf your code already caches a path object, the instance form is more direct:
Path.parse('a.b.c').existIn({ a: { b: { c: 0 } } })
// true
Path.parse('a.b.c').existIn({})
// falsedeleteIn
const values = { user: { profile: { nickname: 'silver', city: 'Shanghai' } } }
Path.deleteIn(values, 'user.profile.city')
// { user: { profile: { nickname: 'silver' } } }The instance method mutates the original object and returns that same reference:
const path = Path.parse('user.profile.city')
const values = { user: { profile: { city: 'Shanghai' } } }
path.deleteIn(values)
path.getIn(values)
// undefinedensureIn
ensureIn means “return the current value, or write and return the default value if it is missing”:
const values = {}
Path.ensureIn(values, 'user.profile.nickname', 'guest')
// 'guest'
Path.ensureIn(values, 'user.profile.nickname', 'other')
// 'guest'The instance form works well with reused Path objects:
const path = Path.parse('user.profile.nickname')
const values = {}
path.ensureIn(values, 'guest')
// 'guest'
path.ensureIn(values, 'other')
// 'guest'Group and destructor examples
This is where path is more expressive than most nested access helpers. You can read or write multiple keys in one expression:
Path.setIn({}, 'a.b.c.{aaa,bbb}', { aaa: 123, bbb: 321 })
// { a: { b: { c: { aaa: 123, bbb: 321 } } } }
Path.getIn(
{ a: { b: { c: { aaa: 123, bbb: 321 } } } },
'a.b.c.{aaa,bbb}',
)
// { aaa: 123, bbb: 321 }Array destructuring style works too:
Path.setIn({}, 'a.b.c.[aaa,bbb]', [123, 321])
// { a: { b: { c: { aaa: 123, bbb: 321 } } } }Object destructuring and nested projection work as well:
const values = {}
Path.setIn(values, 'user.address.{city,zip}', {
city: 'Shanghai',
zip: '200000',
})
Path.getIn(values, 'user.address.{city,zip}')
// { city: 'Shanghai', zip: '200000' }This syntax is especially useful for schemas, field mapping, batch renaming, and structural projection.