Skip to content

Commit 1064082

Browse files
Richienbsindresorhus
andauthoredJul 23, 2022
Rename default export to named export includeKeys() and add excludeKeys() (#18)
Co-authored-by: Sindre Sorhus <sindresorhus@gmail.com>
1 parent 06f7d4b commit 1064082

File tree

6 files changed

+160
-44
lines changed

6 files changed

+160
-44
lines changed
 

‎benchmark.js

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import filterObj from 'filter-obj';
1+
import {includeKeys} from 'filter-obj';
22

33
// Benchmark `filter-obj`.
44
// Higher `loopCount` give more precise results but last longer.
@@ -10,7 +10,7 @@ const benchmark = function (loopCount, objectSize, predicateSize) {
1010

1111
console.time();
1212
for (let index = 0; index < loopCount; index += 1) {
13-
filterObj(bigObject, predicate);
13+
includeKeys(bigObject, predicate);
1414
}
1515

1616
console.timeEnd();

‎index.d.ts

+45-7
Original file line numberDiff line numberDiff line change
@@ -3,35 +3,73 @@ Filter object keys and values into a new object.
33
44
@param object - The source object to filter properties from.
55
@param predicate - Predicate function that detemines whether a property should be assigned to the new object.
6-
@param includeKeys - Property names that should be assigned to the new object.
6+
@param keys - Property names that should be assigned to the new object.
77
88
@example
99
```
10-
import filterObject from 'filter-obj';
10+
import {includeKeys} from 'filter-obj';
1111
1212
const object = {
1313
foo: true,
1414
bar: false
1515
};
1616
17-
const newObject = filterObject(object, (key, value) => value === true);
17+
const newObject = includeKeys(object, (key, value) => value === true);
1818
//=> {foo: true}
1919
20-
const newObject2 = filterObject(object, ['bar']);
20+
const newObject2 = includeKeys(object, ['bar']);
2121
//=> {bar: false}
2222
```
2323
*/
24-
export default function filterObject<ObjectType extends Record<string, any>>(
24+
export function includeKeys<ObjectType extends Record<string, any>>(
2525
object: ObjectType,
2626
predicate: (
2727
key: keyof ObjectType,
2828
value: ObjectType[keyof ObjectType]
2929
) => boolean
3030
): Partial<ObjectType>;
31-
export default function filterObject<
31+
export function includeKeys<
3232
ObjectType extends Record<string, any>,
3333
IncludedKeys extends keyof ObjectType,
3434
>(
3535
object: ObjectType,
36-
includeKeys: readonly IncludedKeys[]
36+
keys: readonly IncludedKeys[]
3737
): Pick<ObjectType, IncludedKeys>;
38+
39+
/**
40+
Filter object keys and values into a new object.
41+
42+
@param object - The source object to filter properties from.
43+
@param predicate - Predicate function that determines whether a property should not be assigned to the new object.
44+
@param keys - Property names that should not be assigned to the new object.
45+
46+
@example
47+
```
48+
import {excludeKeys} from 'filter-obj';
49+
50+
const object = {
51+
foo: true,
52+
bar: false
53+
};
54+
55+
const newObject = excludeKeys(object, (key, value) => value === true);
56+
//=> {bar: false}
57+
58+
const newObject3 = excludeKeys(object, ['bar']);
59+
//=> {foo: true}
60+
```
61+
*/
62+
export function excludeKeys<ObjectType extends Record<string, any>>(
63+
object: ObjectType,
64+
predicate: (
65+
key: keyof ObjectType,
66+
value: ObjectType[keyof ObjectType]
67+
) => boolean
68+
): Partial<ObjectType>;
69+
export function excludeKeys<
70+
ObjectType extends Record<string, any>,
71+
ExcludedKeys extends keyof ObjectType,
72+
>(
73+
object: ObjectType,
74+
keys: readonly ExcludedKeys[]
75+
): Omit<ObjectType, ExcludedKeys>;

‎index.js

+10-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
export default function filterObject(object, predicate) {
1+
export function includeKeys(object, predicate) {
22
const result = {};
33

44
if (Array.isArray(predicate)) {
@@ -31,3 +31,12 @@ export default function filterObject(object, predicate) {
3131

3232
return result;
3333
}
34+
35+
export function excludeKeys(object, predicate) {
36+
if (Array.isArray(predicate)) {
37+
const set = new Set(predicate);
38+
return includeKeys(object, key => !set.has(key));
39+
}
40+
41+
return includeKeys(object, (key, value, object) => !predicate(key, value, object));
42+
}

‎index.test-d.ts

+21-6
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,37 @@
11
import {expectType, expectError} from 'tsd';
2-
import filterObject from './index.js';
2+
import {includeKeys, excludeKeys} from './index.js';
33

44
const object = {
55
foo: 'foo',
66
bar: 1,
77
};
88

99
expectType<Partial<typeof object>>(
10-
filterObject(object, (key, value) => {
10+
includeKeys(object, (key, value) => {
1111
expectType<'foo' | 'bar'>(key);
1212
expectType<string | number>(value);
1313

1414
return false;
1515
}),
1616
);
1717
expectError<typeof object>(
18-
filterObject(object, () => false),
18+
includeKeys(object, () => false),
1919
);
20-
expectType<{foo: string}>(filterObject(object, ['foo']));
21-
expectError<typeof object>(filterObject(object, ['foo']));
22-
expectError(filterObject(object, ['baz']));
20+
expectType<{foo: string}>(includeKeys(object, ['foo']));
21+
expectError<typeof object>(includeKeys(object, ['foo']));
22+
expectError(includeKeys(object, ['baz']));
23+
24+
expectType<Partial<typeof object>>(
25+
excludeKeys(object, (key, value) => {
26+
expectType<'foo' | 'bar'>(key);
27+
expectType<string | number>(value);
28+
29+
return false;
30+
}),
31+
);
32+
expectError<typeof object>(
33+
excludeKeys(object, () => false),
34+
);
35+
expectType<{bar: number}>(excludeKeys(object, ['foo']));
36+
expectError<typeof object>(excludeKeys(object, ['foo']));
37+
expectError(excludeKeys(object, ['baz']));

‎readme.md

+16-8
Original file line numberDiff line numberDiff line change
@@ -11,26 +11,34 @@ npm install filter-obj
1111
## Usage
1212

1313
```js
14-
import filterObject from 'filter-obj';
14+
import {includeKeys, excludeKeys} from 'filter-obj';
1515

1616
const object = {
1717
foo: true,
1818
bar: false
1919
};
2020

21-
const newObject = filterObject(object, (key, value) => value === true);
21+
const newObject = includeKeys(object, (key, value) => value === true);
2222
//=> {foo: true}
2323

24-
const newObject2 = filterObject(object, ['bar']);
24+
const newObject2 = includeKeys(object, ['bar']);
2525
//=> {bar: false}
26+
27+
const newObject = excludeKeys(object, (key, value) => value === true);
28+
//=> {bar: false}
29+
30+
const newObject3 = excludeKeys(object, ['bar']);
31+
//=> {foo: true}
2632
```
2733

2834
## API
2935

3036
Symbol keys are not copied over to the new object.
3137

32-
### filterObject(source, filter)
33-
### filterObject(source, includeKeys)
38+
### includeKeys(source, filter)
39+
### includeKeys(source, keys)
40+
### excludeKeys(source, filter)
41+
### excludeKeys(source, keys)
3442

3543
#### source
3644

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

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

45-
A predicate function that detemines whether a property should be assigned to the new object.
53+
A predicate function that detemines whether a property should be filtered.
4654

47-
#### includeKeys
55+
#### keys
4856

4957
Type: `string[]`
5058

51-
An array of property names that should be assigned to the new object.
59+
An array of property names to be filtered.
5260

5361
## Related
5462

‎test.js

+66-20
Original file line numberDiff line numberDiff line change
@@ -1,48 +1,94 @@
11
import test from 'ava';
2-
import filterObject from './index.js';
2+
import {includeKeys, excludeKeys} from './index.js';
33

4-
test('function predicate returns a boolean', t => {
5-
t.is(Object.keys(filterObject({foo: true, bar: false}, () => true)).length, 2);
6-
t.is(Object.keys(filterObject({foo: true, bar: false}, () => false)).length, 0);
4+
test('includeKeys: function predicate returns a boolean', t => {
5+
t.is(Object.keys(includeKeys({foo: true, bar: false}, () => true)).length, 2);
6+
t.is(Object.keys(includeKeys({foo: true, bar: false}, () => false)).length, 0);
77
});
88

9-
test('function predicate passes the key as argument', t => {
10-
t.true(filterObject({foo: true}, key => key === 'foo').foo);
9+
test('includeKeys: function predicate passes the key as argument', t => {
10+
t.true(includeKeys({foo: true}, key => key === 'foo').foo);
1111
});
1212

13-
test('function predicate passes the value as argument', t => {
14-
t.is(filterObject({foo: 'test'}, (key, value) => value === 'test').foo, 'test');
13+
test('includeKeys: function predicate passes the value as argument', t => {
14+
t.is(includeKeys({foo: 'test'}, (key, value) => value === 'test').foo, 'test');
1515
});
1616

17-
test('function predicate passes the object as argument', t => {
18-
t.true(filterObject({foo: true}, (key, value, object) => object.foo).foo);
17+
test('includeKeys: function predicate passes the object as argument', t => {
18+
t.true(includeKeys({foo: true}, (key, value, object) => object.foo).foo);
1919
});
2020

21-
test('array predicate', t => {
22-
t.deepEqual(Object.keys(filterObject({foo: true, bar: false}, ['foo'])), ['foo']);
21+
test('includeKeys: array predicate', t => {
22+
t.deepEqual(Object.keys(includeKeys({foo: true, bar: false}, ['foo'])), ['foo']);
2323
});
2424

25-
test('symbol properties are omitted', t => {
25+
test('includeKeys: symbol properties are omitted', t => {
2626
const symbol = Symbol('test');
2727
const input = {[symbol]: true};
28-
t.is(filterObject(input, () => true)[symbol], undefined);
28+
t.is(includeKeys(input, () => true)[symbol], undefined);
2929
});
3030

31-
test('non-enumerable properties are omitted', t => {
31+
test('includeKeys: non-enumerable properties are omitted', t => {
3232
const input = Object.defineProperty({}, 'test', {value: true, enumerable: false});
33-
t.is(filterObject(input, () => true).test, undefined);
33+
t.is(includeKeys(input, () => true).test, undefined);
3434
});
3535

36-
test('inherited properties are omitted', t => {
36+
test('includeKeys: inherited properties are omitted', t => {
3737
const Parent = class {
3838
test() {}
3939
};
4040
const Child = class extends Parent {};
4141
const input = new Child();
42-
t.is(filterObject(input, () => true).test, undefined);
42+
t.is(includeKeys(input, () => true).test, undefined);
4343
});
4444

45-
test('__proto__ keys', t => {
45+
test('includeKeys: __proto__ keys', t => {
4646
const input = {__proto__: {foo: true}};
47-
t.deepEqual(filterObject(input, () => true), input);
47+
t.deepEqual(includeKeys(input, () => true), input);
48+
});
49+
50+
test('excludeKeys: function predicate returns a boolean', t => {
51+
t.is(Object.keys(excludeKeys({foo: true, bar: false}, () => true)).length, 0);
52+
t.is(Object.keys(excludeKeys({foo: true, bar: false}, () => false)).length, 2);
53+
});
54+
55+
test('excludeKeys: function predicate passes the key as argument', t => {
56+
t.true(excludeKeys({foo: true}, key => key !== 'foo').foo);
57+
});
58+
59+
test('excludeKeys: function predicate passes the value as argument', t => {
60+
t.is(excludeKeys({foo: 'test'}, (key, value) => value !== 'test').foo, 'test');
61+
});
62+
63+
test('excludeKeys: function predicate passes the object as argument', t => {
64+
t.true(excludeKeys({foo: true}, (key, value, object) => !object.foo).foo);
65+
});
66+
67+
test('excludeKeys: array predicate', t => {
68+
t.deepEqual(Object.keys(excludeKeys({foo: true, bar: false}, ['bar'])), ['foo']);
69+
});
70+
71+
test('excludeKeys: symbol properties are omitted', t => {
72+
const symbol = Symbol('test');
73+
const input = {[symbol]: true};
74+
t.is(excludeKeys(input, () => false)[symbol], undefined);
75+
});
76+
77+
test('excludeKeys: non-enumerable properties are omitted', t => {
78+
const input = Object.defineProperty({}, 'test', {value: true, enumerable: false});
79+
t.is(excludeKeys(input, () => false).test, undefined);
80+
});
81+
82+
test('excludeKeys: inherited properties are omitted', t => {
83+
const Parent = class {
84+
test() {}
85+
};
86+
const Child = class extends Parent {};
87+
const input = new Child();
88+
t.is(excludeKeys(input, () => false).test, undefined);
89+
});
90+
91+
test('excludeKeys: __proto__ keys', t => {
92+
const input = {__proto__: {foo: true}};
93+
t.deepEqual(excludeKeys(input, () => false), input);
4894
});

0 commit comments

Comments
 (0)
Please sign in to comment.