dig-ts
v1.0.8
Published
Type safe deep object selector
Downloads
699
Maintainers
Readme
dig nested object selector
dig-ts
handles nested objects and arrays,
without throwing error Cannot read property 'x' of undefined
, while fully supporting typescript..
Features
- Typescript support, for proper code-completion while coding.
- Supported by all browsers
- Light weight
- Supports arrays, nested get, set, delete.
- Transform any structure to any other with find, filter and many other features.
Install
npm i --save dig-ts
Requirements
- TypeScript >= 2.9
Example dig
Usage
import { dig } from 'dig-ts';
// Let's pretend abc is unpredictable and maybe incomplete.
const response = {a:
{b: [
{c: 'First'},
{c: 'Second'}
]
}
};
let first = dig(response, 'a', 'b', 0, 'c').get(); // 'First'
let maybe = dig(response, 'a', 'b', 9, 'c').get(); // undefined
let str = dig(response, 'a', 'b', 9, 'c').get('unknown'); // 'unknown'
shorter format
digUp
immediately returns a value, without .get()
.
import { digUp } from 'dig-ts';
// Let's say response is as above.
let first = digUp(response, 'a', 'b', 0, 'c'); // 'First'
let maybe = digUp(response, 'a', 'b', 9, 'c'); // undefined
let str = digUp(response, ['a', 'b', 9, 'c'], 'unknown'); // 'unknown'
dig
offers a lot more, but digUp
is fine for reading only.
As you can see, it accepts a default value, like 'unknown'.
Just wrap the keys in an array.
The shorter format is also available in a separate small package digup-ts
.
Typescript support
Typescript is fully supported, so your editor points out missing properties.
let X = dig(response, 'X').get(); // typescript error 'X' doesn't exist...
Example data
The examples below all use the following data:
const store = {
customers: [
{name: 'A', age:20}, // missing purchases
{name: 'B', // missing age
purchases: [
{name: 'shoes', price:10}
]
},
{name: 'C', age:60,
purchases: [
{name: 'flipflops'}, // missing price
{name: 'boots', price:20}
]
},
{}, // missing name + purchases
{purchases: [{name: 'boots', price:20}]} // missing name
]
}
Update
To set the price of first boots to 22:
dig(store).collect('customer', 'purchases')
.filter(purchase=>purchase.name=='boots')
.dig(0, 'price')
.set(10)
Delete
To remove the last customer:
dig(store, 'customer', last).delete()
Array.find among keys
Use a function to find a single item in an array.
import { dig, digUp, last } from 'dig-ts';
// Get last purchase of customer B using a function
const customerB = dig(store, 'customers', cust=>cust.name=='B', 'purchases', last).get();
// Similar with shorter format.
const customerC = digUp(store, 'customers', cust=>cust.name=='C', 'purchases', last);
// Get price of boots of customer C (or 0 if not found)
const price = dig(store, 'customers', cust=>cust.name=='C', 'purchases', pur=>pur.name=='boots', 'price').get(0);
// 'last' function is included in dig-ts
const lastSale = dig(store, 'customers', last, 'purchases', last).get(); // boots object
Array.filter
, Array.sort
and chaining
// Let's take 'store' from above.
// 1. Who bought expensive stuff?
const goodCustomers = dig(store, 'customers')
.filter(customer=>
dig(customer, 'purchases')
.some(purchase=>purchase.price>10)
);
// 2. Which expensive products were made by the last old customer?
const bigOldSales = dig(store, 'customers')
.filter(customer=>customer.age>=60)
.dig(last, 'purchases')
.filter(product=>product.price>10);
// 3. What was the name of that last once?
bigOldSales.dig(last, 'name').get();
As you can tell by examples 2 and 3 above,
the .dig
method is added to the result of filter
and sort
.
This allows us to keep on digging, aka method chaining:
In case you're wondering why reduce
and map
don't return a DigArray with .dig
method:
map and reduce can change the array content,
making it unpredictable for typescript.
exists
Check if a value exists:
if (dig(store, 'customers', 99, 'products', 0).exists()) {
// ...welcome 100th customer, if (s)he bought anything.
}
return
Returning a custom object.
const bootBuyers = dig(store, 'customers')
.filter(customer=>dig(customer, 'purchases', purchase=>purchase.name==='boots')
.return(customers => ({
count: customers.length,
first: customers.dig(0),
last: customers.dig(last)
}));
Putting it all together
Here's a more complex example, using the example data above, combining several methods.
import { dig, last, max, min } from 'dig-ts';
const summary = dig(response, 'data', 'customers')
.return(customers => ({
purchaseCount: customers.collect('purchases').length,
biggestPurchase: customers.max('purchases', 'price'),
biggestPurchaseByLastOldCustomer: customers.filter(customer=>customer.age>=60)
.dig(last, 'products').max('price')
,
topCustomer: customers
.find(max('purchases', 'length'))
.return(cust=>({
name: cust.name,
...dig(cust, 'purchases').return(purchases => ({
itemCount: purchases.length,
topPurchase: purchases.max('price'),
totalPrice: purchases.sum('price')
}))
}))
})
);
summary will be:
{
purchaseCount: 4,
biggestPurchase: 20,
biggestPurchaseByLastOldCustomer: 20,
topCustomer: {
name: 'C',
itemCount: 2,
topPurchase: 20
totalPrice: 20
}
}
Now to forget name of top client:
dig(summary, 'topCustomer', 'customerName').delete()
License
dig-ts
is MIT Licensed.