Skip to content
Permalink

Comparing changes

Choose two branches to see what’s changed or to start a new pull request. If you need to, you can also or learn more about diff comparisons.

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also . Learn more about diff comparisons here.
base repository: sindresorhus/filter-obj
Failed to load repositories. Confirm that selected base ref is valid, then try again.
Loading
base: v3.0.0
Choose a base ref
...
head repository: sindresorhus/filter-obj
Failed to load repositories. Confirm that selected head ref is valid, then try again.
Loading
compare: v4.0.0
Choose a head ref
  • 9 commits
  • 10 files changed
  • 3 contributors

Commits on Jun 3, 2022

  1. Add more tests (#13)

    ehmicky authored Jun 3, 2022
    Copy the full SHA
    4a0ca44 View commit details
  2. Verified

    This commit was created on GitHub.com and signed with GitHub’s verified signature.
    Copy the full SHA
    6098d8d View commit details
  3. Add note about symbols

    sindresorhus committed Jun 3, 2022
    Copy the full SHA
    6a82db0 View commit details
  4. Improve performance (#14)

    ehmicky authored Jun 3, 2022
    Copy the full SHA
    897518a View commit details
  5. Copy the full SHA
    3f6661c View commit details

Commits on Jul 8, 2022

  1. Meta tweaks

    sindresorhus committed Jul 8, 2022
    Copy the full SHA
    06f7d4b View commit details

Commits on Jul 23, 2022

  1. Rename default export to named export includeKeys() and add `exclud…

    …eKeys()` (#18)
    
    Co-authored-by: Sindre Sorhus <sindresorhus@gmail.com>
    Richienb and sindresorhus authored Jul 23, 2022
    Copy the full SHA
    1064082 View commit details
  2. Require Node.js 14

    sindresorhus committed Jul 23, 2022
    Copy the full SHA
    25fdfe6 View commit details
  3. 4.0.0

    sindresorhus committed Jul 23, 2022
    Copy the full SHA
    36e5f3a View commit details
Showing with 260 additions and 53 deletions.
  1. +4 −0 .github/funding.yml
  2. +3 −0 .github/security.md
  3. +3 −2 .github/workflows/main.yml
  4. +31 −0 benchmark.js
  5. +45 −7 index.d.ts
  6. +35 −10 index.js
  7. +21 −6 index.test-d.ts
  8. +11 −6 package.json
  9. +20 −10 readme.md
  10. +87 −12 test.js
4 changes: 4 additions & 0 deletions .github/funding.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
github: sindresorhus
open_collective: sindresorhus
tidelift: npm/filter-obj
custom: https://sindresorhus.com/donate
3 changes: 3 additions & 0 deletions .github/security.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# Security Policy

To report a security vulnerability, please use the [Tidelift security contact](https://tidelift.com/security). Tidelift will coordinate the fix and disclosure.
5 changes: 3 additions & 2 deletions .github/workflows/main.yml
Original file line number Diff line number Diff line change
@@ -10,10 +10,11 @@ jobs:
fail-fast: false
matrix:
node-version:
- 18
- 16
steps:
- uses: actions/checkout@v2
- uses: actions/setup-node@v2
- uses: actions/checkout@v3
- uses: actions/setup-node@v3
with:
node-version: ${{ matrix.node-version }}
- run: npm install
31 changes: 31 additions & 0 deletions benchmark.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import {includeKeys} from 'filter-obj';

// Benchmark `filter-obj`.
// Higher `loopCount` give more precise results but last longer.
// `objectSize` gives different results based on how big the input object is.
// `predicateSize` is similar but for predicate arrays. When `undefined`, a predicate function is used instead.
const benchmark = function (loopCount, objectSize, predicateSize) {
const bigObject = Object.fromEntries(Array.from({length: objectSize}, getObjectKeyPair));
const predicate = predicateSize === undefined ? isEven : Array.from({length: predicateSize}, getPredicateKey);

console.time();
for (let index = 0; index < loopCount; index += 1) {
includeKeys(bigObject, predicate);
}

console.timeEnd();
};

const getObjectKeyPair = function (_, index) {
return [`a${index}`, index];
};

const getPredicateKey = function (_, index) {
return `a${index}`;
};

const isEven = function (key, value) {
return value % 2 === 0;
};

benchmark(1e3, 1e4);
52 changes: 45 additions & 7 deletions index.d.ts
Original file line number Diff line number Diff line change
@@ -3,35 +3,73 @@ Filter object keys and values into a new object.
@param object - The source object to filter properties from.
@param predicate - Predicate function that detemines whether a property should be assigned to the new object.
@param includeKeys - Property names that should be assigned to the new object.
@param keys - Property names that should be assigned to the new object.
@example
```
import filterObject from 'filter-obj';
import {includeKeys} from 'filter-obj';
const object = {
foo: true,
bar: false
};
const newObject = filterObject(object, (key, value) => value === true);
const newObject = includeKeys(object, (key, value) => value === true);
//=> {foo: true}
const newObject2 = filterObject(object, ['bar']);
const newObject2 = includeKeys(object, ['bar']);
//=> {bar: false}
```
*/
export default function filterObject<ObjectType extends Record<string, any>>(
export function includeKeys<ObjectType extends Record<string, any>>(
object: ObjectType,
predicate: (
key: keyof ObjectType,
value: ObjectType[keyof ObjectType]
) => boolean
): Partial<ObjectType>;
export default function filterObject<
export function includeKeys<
ObjectType extends Record<string, any>,
IncludedKeys extends keyof ObjectType,
>(
object: ObjectType,
includeKeys: readonly IncludedKeys[]
keys: readonly IncludedKeys[]
): Pick<ObjectType, IncludedKeys>;

/**
Filter object keys and values into a new object.
@param object - The source object to filter properties from.
@param predicate - Predicate function that determines whether a property should not be assigned to the new object.
@param keys - Property names that should not be assigned to the new object.
@example
```
import {excludeKeys} from 'filter-obj';
const object = {
foo: true,
bar: false
};
const newObject = excludeKeys(object, (key, value) => value === true);
//=> {bar: false}
const newObject3 = excludeKeys(object, ['bar']);
//=> {foo: true}
```
*/
export function excludeKeys<ObjectType extends Record<string, any>>(
object: ObjectType,
predicate: (
key: keyof ObjectType,
value: ObjectType[keyof ObjectType]
) => boolean
): Partial<ObjectType>;
export function excludeKeys<
ObjectType extends Record<string, any>,
ExcludedKeys extends keyof ObjectType,
>(
object: ObjectType,
keys: readonly ExcludedKeys[]
): Omit<ObjectType, ExcludedKeys>;
45 changes: 35 additions & 10 deletions index.js
Original file line number Diff line number Diff line change
@@ -1,17 +1,42 @@
export default function filterObject(object, predicate) {
export function includeKeys(object, predicate) {
const result = {};
const isArray = Array.isArray(predicate);

for (const [key, value] of Object.entries(object)) {
if (isArray ? predicate.includes(key) : predicate(key, value, object)) {
Object.defineProperty(result, key, {
value,
writable: true,
enumerable: true,
configurable: true,
});
if (Array.isArray(predicate)) {
const set = new Set(predicate);
for (const key of Object.keys(object)) {
if (set.has(key)) {
const value = object[key];
Object.defineProperty(result, key, {
value,
writable: true,
enumerable: true,
configurable: true,
});
}
}
} else {
// `for ... of Object.keys()` is faster than `for ... of Object.entries()`.
for (const key of Object.keys(object)) {
const value = object[key];
if (predicate(key, value, object)) {
Object.defineProperty(result, key, {
value,
writable: true,
enumerable: true,
configurable: true,
});
}
}
}

return result;
}

export function excludeKeys(object, predicate) {
if (Array.isArray(predicate)) {
const set = new Set(predicate);
return includeKeys(object, key => !set.has(key));
}

return includeKeys(object, (key, value, object) => !predicate(key, value, object));
}
27 changes: 21 additions & 6 deletions index.test-d.ts
Original file line number Diff line number Diff line change
@@ -1,22 +1,37 @@
import {expectType, expectError} from 'tsd';
import filterObject from './index.js';
import {includeKeys, excludeKeys} from './index.js';

const object = {
foo: 'foo',
bar: 1,
};

expectType<Partial<typeof object>>(
filterObject(object, (key, value) => {
includeKeys(object, (key, value) => {
expectType<'foo' | 'bar'>(key);
expectType<string | number>(value);

return false;
}),
);
expectError<typeof object>(
filterObject(object, () => false),
includeKeys(object, () => false),
);
expectType<{foo: string}>(filterObject(object, ['foo']));
expectError<typeof object>(filterObject(object, ['foo']));
expectError(filterObject(object, ['baz']));
expectType<{foo: string}>(includeKeys(object, ['foo']));
expectError<typeof object>(includeKeys(object, ['foo']));
expectError(includeKeys(object, ['baz']));

expectType<Partial<typeof object>>(
excludeKeys(object, (key, value) => {
expectType<'foo' | 'bar'>(key);
expectType<string | number>(value);

return false;
}),
);
expectError<typeof object>(
excludeKeys(object, () => false),
);
expectType<{bar: number}>(excludeKeys(object, ['foo']));
expectError<typeof object>(excludeKeys(object, ['foo']));
expectError(excludeKeys(object, ['baz']));
17 changes: 11 additions & 6 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "filter-obj",
"version": "3.0.0",
"version": "4.0.0",
"description": "Filter object keys and values into a new object",
"license": "MIT",
"repository": "sindresorhus/filter-obj",
@@ -12,8 +12,9 @@
},
"type": "module",
"exports": "./index.js",
"types": "./index.d.ts",
"engines": {
"node": "^12.20.0 || ^14.13.1 || >=16.0.0"
"node": ">=14.16"
},
"scripts": {
"test": "xo && ava && tsd"
@@ -30,11 +31,15 @@
"value",
"values",
"iterate",
"iterator"
"iterator",
"include",
"exclude",
"pick",
"omit"
],
"devDependencies": {
"ava": "^3.15.0",
"tsd": "^0.17.0",
"xo": "^0.44.0"
"ava": "^4.3.1",
"tsd": "^0.22.0",
"xo": "^0.51.0"
}
}
30 changes: 20 additions & 10 deletions readme.md
Original file line number Diff line number Diff line change
@@ -4,31 +4,41 @@
## Install

```
$ npm install filter-obj
```sh
npm install filter-obj
```

## Usage

```js
import filterObject from 'filter-obj';
import {includeKeys, excludeKeys} from 'filter-obj';

const object = {
foo: true,
bar: false
};

const newObject = filterObject(object, (key, value) => value === true);
const newObject = includeKeys(object, (key, value) => value === true);
//=> {foo: true}

const newObject2 = filterObject(object, ['bar']);
const newObject2 = includeKeys(object, ['bar']);
//=> {bar: false}

const newObject = excludeKeys(object, (key, value) => value === true);
//=> {bar: false}

const newObject3 = excludeKeys(object, ['bar']);
//=> {foo: true}
```

## API

### filterObject(source, filter)
### filterObject(source, includeKeys)
Symbol keys are not copied over to the new object.

### includeKeys(source, filter)
### includeKeys(source, keys)
### excludeKeys(source, filter)
### excludeKeys(source, keys)

#### source

@@ -40,13 +50,13 @@ The source object to filter properties from.

Type: `(sourceKey, sourceValue, source) => boolean`

A predicate function that detemines whether a property should be assigned to the new object.
A predicate function that detemines whether a property should be filtered.

#### includeKeys
#### keys

Type: `string[]`

An array of property names that should be assigned to the new object.
An array of property names to be filtered.

## Related

Loading