Clojure's core/update_in in TypeScript
✓ Verified: Clojure 1.12
Examples tested against actual runtime. CI re-verifies continuously. Only documented examples are tested.
How to use
Install via yarn add locutus and import:
import { update_in } from 'locutus/clojure/core/update_in'.
Or with CommonJS: const { update_in } = require('locutus/clojure/core/update_in')
Use a bundler that supports tree-shaking so you only ship the functions you actually use.
Vite ,
webpack ,
Rollup , and
Parcel
all handle this. For server-side use this is less of a concern.
Examples
These examples are extracted from test cases that automatically verify our functions against their native counterparts.
# code expected result
1 update_in({a: {b: 1}}, ['a', 'b'], (n) => Number(n) + 1){a: {b: 2}}
2 update_in({a: {}}, ['a', 'b'], (v) => (v === undefined ? 10 : Number(v))){a: {b: 10}}
3 update_in([1, {x: 3}], [1, 'x'], (n) => Number(n) * 2)[1, {x: 6}]
Notes
Here's what our current TypeScript equivalent to Clojure's core/update_in looks like.
Copy code
type PathKey = string | number type Updater = (currentValue : unknown , ...args : unknown [] ) => unknown function isRecordLike (value : unknown ): value is Record <string | number , unknown > { return typeof value === 'object' && value !== null } function cloneForKey (value : unknown , nextKey ?: PathKey ): Record <string | number , unknown > | unknown [] { if (Array .isArray (value)) { return value.slice () } if (isRecordLike (value)) { return { ...value } } return typeof nextKey === 'number' ? [] : {} } export function update_in (value : unknown , keys : PathKey [] | unknown , updater : Updater , ...args : unknown [] ): unknown { if (typeof updater !== 'function' ) { throw new TypeError ('update_in(): updater must be a function' ) } if (!Array .isArray (keys)) { return updater (value, ...args) } if (keys.length === 0 ) { return updater (value, ...args) } const root = cloneForKey (value, keys[0 ]) let sourceCursor : unknown = value let targetCursor : Record <string | number , unknown > | unknown [] = root for (let i = 0 ; i < keys.length - 1 ; i++) { const key = keys[i] const nextKey = keys[i + 1 ] if (key === undefined || nextKey === undefined ) { continue } const sourceNext = sourceCursor !== null && typeof sourceCursor === 'object' ? (sourceCursor as Record <string | number , unknown >)[key] : undefined const clonedNext = cloneForKey (sourceNext, nextKey) ;(targetCursor as Record <string | number , unknown >)[key] = clonedNext sourceCursor = sourceNext targetCursor = clonedNext } const leafKey = keys[keys.length - 1 ] if (leafKey === undefined ) { return root } const currentLeafValue = sourceCursor !== null && typeof sourceCursor === 'object' ? (sourceCursor as Record <string | number , unknown >)[leafKey] : undefined ;(targetCursor as Record <string | number , unknown >)[leafKey] = updater (currentLeafValue, ...args) return root }
function isRecordLike (value ) { return typeof value === 'object' && value !== null } function cloneForKey (value, nextKey ) { if (Array .isArray (value)) { return value.slice () } if (isRecordLike (value)) { return { ...value } } return typeof nextKey === 'number' ? [] : {} } export function update_in (value, keys, updater, ...args ) { if (typeof updater !== 'function' ) { throw new TypeError ('update_in(): updater must be a function' ) } if (!Array .isArray (keys)) { return updater (value, ...args) } if (keys.length === 0 ) { return updater (value, ...args) } const root = cloneForKey (value, keys[0 ]) let sourceCursor = value let targetCursor = root for (let i = 0 ; i < keys.length - 1 ; i++) { const key = keys[i] const nextKey = keys[i + 1 ] if (key === undefined || nextKey === undefined ) { continue } const sourceNext = sourceCursor !== null && typeof sourceCursor === 'object' ? sourceCursor[key] : undefined const clonedNext = cloneForKey (sourceNext, nextKey) targetCursor[key] = clonedNext sourceCursor = sourceNext targetCursor = clonedNext } const leafKey = keys[keys.length - 1 ] if (leafKey === undefined ) { return root } const currentLeafValue = sourceCursor !== null && typeof sourceCursor === 'object' ? sourceCursor[leafKey] : undefined targetCursor[leafKey] = updater (currentLeafValue, ...args) return root }
Improve this function
Locutus is a community effort following
The McDonald's Theory :
we ship first iterations, hoping others will improve them.
If you see something that could be better, we'd love your contribution.
View on GitHub
·
Edit on GitHub
·
View Raw
We have 14 Clojure functions so far - help us add more
Got a rainy Sunday afternoon and a taste for a porting puzzle?
Get inspiration from
ClojureDocs .
Click "New file" in the appropriate folder
on GitHub .
This will fork the project to your account, directly add the file to it, and send a
Pull Request to us.
We will then review it. If it's useful to the project and in line with our
contributing guidelines
your work will become part of Locutus and you'll be automatically credited
in the authors
section accordingly.
« More Clojure core functions
Star