A complement to match-iz for filtering objects, arrays, and Map/Set based on a match-iz pattern.
- 🗺 byPattern() for map/filter
- 📥 sift() an object
- 📁 sift() an array
- 🗂 sift() an array into multiple buckets
- 🔁 siftr() — curried sift
- 🗺 sift() a Map or Set
- 🔢 sift() an iterable
- 🧩 TypeScript
- 📖 Documentation
- 📀 Install / Use
import { byPattern } from 'sift-r'
const filtered = [
{ user: 'barney', age: 36, active: false },
{ user: 'fred', age: 40, active: true },
{ user: 'pebbles', age: 1, active: false }
].filter(
byPattern({
age: 36
})
)
// filtered ===
// [
// { user: 'barney', age: 36, active: false }
// ]
import { pluck, isNumber } from 'match-iz'
const mapped = [
{ user: 'barney', age: 36, active: false },
{ user: 'fred', age: 40, active: true },
{ user: 'pebbles', age: 1, active: false },
{ user: '', age: 'not-a-number', active: true }
].map(
byPattern({
age: pluck(isNumber)
})
)
// mapped === [36, 40, 1, undefined]import { sift } from 'sift-r'
const isString = x => typeof x === 'string'
const isNumber = x => typeof x === 'number'
const [strValues, numValues, neither] = sift(
{
title: 'header',
slug: 1,
markdown: '# header',
footer: undefined
},
[isString, isNumber]
)
// strValues ===
// {
// title: 'header',
// markdown: '# header'
// }
// numValues ===
// {
// slug: 1
// }
// neither ===
// {
// footer: undefined
// }(+using match-iz pattern-helpers)
import { sift } from 'sift-r'
import { gte, allOf } from 'match-iz'
const users = [
{ user: 'barney', age: 36, active: false },
{ user: 'fred', age: 40, active: true },
{ user: 'pebbles', age: 1, active: true }
]
const isActive = { active: true }
const isGrownUp = { age: gte(18) }
const isActiveGrownUp = allOf(isActive, isGrownUp)
const [activeGrownUps, everyoneElse] = sift(users, isActiveGrownUp)
// activeGrownUps ===
// [
// { user: 'fred', age: 40, active: true }
// ]
// everyoneElse ===
// [
// { user: 'barney', age: 36, active: false },
// { user: 'pebbles', age: 1, active: true }
// ]import { sift } from 'sift-r'
import { lt } from 'match-iz'
const [oneYearOlds, lessThan40, theRest] = sift(
[
{ user: 'barney', age: 36, active: false },
{ user: 'fred', age: 40, active: true },
{ user: 'pebbles', age: 1, active: false }
],
{ age: 1, active: false },
{ age: lt(40) }
)
// oneYearOlds ===
// [{ user: 'pebbles', age: 1, active: false }]
// lessThan40 ===
// [{ user: 'barney', age: 36, active: false }]
// theRest ===
// [{ user: 'fred', age: 40, active: true }]siftr(...schema) returns a function (input) => sift(input, ...schema) so you can fix the patterns once and reuse them (pipelines, .map, multiple collections).
import { siftr } from 'sift-r'
import { pluck, isNumber, lt } from 'match-iz'
const users = [
{ user: 'barney', age: 36, active: false },
{ user: 'fred', age: 40, active: true },
{ user: 'pebbles', age: 1, active: false }
]
const splitByAge = siftr({ age: 1 }, { age: lt(40) })
const [oneYearOlds, lessThan40, theRest] = splitByAge(users)
// Same schema, other inputs:
splitByAge(new Set(users))
splitByAge(users) // again
// With match-iz pluck: match buckets hold plucked payloads
const inactiveAges = siftr({ active: false, age: pluck(isNumber) })
const [ages, rest] = inactiveAges(users)
// ages === [36, 1]
// rest === [{ user: 'fred', age: 40, active: true }]Set example:
import { sift } from 'sift-r'
import { lt } from 'match-iz'
const [oneYearOlds, lessThan40, theRest] = sift(
new Set([
{ user: 'barney', age: 36, active: false },
{ user: 'fred', age: 40, active: true },
{ user: 'pebbles', age: 1, active: false }
]),
{ age: 1, active: false },
{ age: lt(40) }
)
// oneYearOlds ===
// new Set([
// { user: 'pebbles', age: 1, active: false }
// ])
// lessThan40 ===
// new Set([
// { user: 'barney', age: 36, active: false }
// ])
// theRest ===
// new Set([
// { user: 'fred', age: 40, active: true }
// ])Map example:
import { sift } from 'sift-r'
import { lt } from 'match-iz'
const [oneYearOlds, lessThan40, theRest] = sift(
new Map([
[0, { user: 'barney', age: 36, active: false }],
[1, { user: 'fred', age: 40, active: true }],
[2, { user: 'pebbles', age: 1, active: false }]
]),
{ age: 1, active: false },
{ age: lt(40) }
)
// oneYearOlds ===
// new Map([
// [2, { user: 'pebbles', age: 1, active: false }]
// ])
// lessThan40 ===
// new Map([
// [0, { user: 'barney', age: 36, active: false }]
// ])
// theRest ===
// new Map([
// [1, { user: 'fred', age: 40, active: true }]
// ])import { sift } from 'sift-r'
import { lt } from 'match-iz'
function* flintstones() {
yield { user: 'barney', age: 36, active: false }
yield { user: 'fred', age: 40, active: true }
yield { user: 'pebbles', age: 1, active: false }
}
const [oneYearOlds, lessThan40, theRest] = sift(
flintstones(),
{ age: 1, active: false },
{ age: lt(40) }
)
// oneYearOlds ===
// [{ user: 'pebbles', age: 1, active: false }]
// lessThan40 ===
// [{ user: 'barney', age: 36, active: false }]
// theRest ===
// [{ user: 'fred', age: 40, active: true }]sift-r ships detailed types in index.d.ts (no separate @types package).
| Feature | Behaviour |
|---|---|
| Container arity | N patterns → N match buckets + 1 remainder (Array / Set / Map / iterable / pojo) |
| Type guards | Up to five (x) => x is U arms: match buckets are Extract, remainder is Exclude of all matched unions |
pluck (match-iz) |
Match buckets use the plucked payload type (MatchPayload); remainder keeps full elements |
siftr |
Same typing as sift, curried |
byPattern |
map/filter helper; with pluck, map results are payload | undefined |
import { sift, siftr, byPattern } from 'sift-r'
import { pluck, isNumber, isString } from 'match-iz'
const isStr = (x: unknown): x is string => typeof x === 'string'
const isNum = (x: unknown): x is number => typeof x === 'number'
// Multi type-guard partition
const [strings, numbers, rest] = sift(
['a', 1, true] as Array<string | number | boolean>,
isStr,
isNum
)
// strings: string[]; numbers: number[]; rest: boolean[]
// Pluck transform in a reusable sifter
type User = { user: string; age: number; active: boolean }
const inactiveAges = siftr({ active: false, age: pluck(isNumber) })
const [ages, others] = inactiveAges([] as User[])
// ages: number[]; others: User[]
// byPattern + pluck
;([] as User[]).map(byPattern({ age: pluck(isNumber) }))
// Array<number | undefined>Requires match-iz ≥ 5.1 for public pluck type helpers used by these definitions.
$ pnpm i sift-r
Supports import/require for ESM/CJS ("type": "module" package with dual exports).
Browser/UMD version here (global name is siftr — not to be confused with the siftr function export):
<script src="https://unpkg.com/sift-r/dist/browser/sift-r.browser.js"></script>
<script>
const { sift, siftr, byPattern } = siftr
</script>sift() has several call-signatures, all of which are documented on the Wiki. See also the TypeScript section above for typing behaviour.
sift-r was written by Conan Theobald.
I hope you found it useful! If so, I like coffee ☕️ :)
MIT licensed: See LICENSE