strip-undefined-values 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +135 -0
- package/dist/index.cjs +48 -0
- package/dist/index.d.ts +58 -0
- package/dist/index.js +45 -0
- package/package.json +57 -0
package/README.md
ADDED
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
# strip-undefined-values
|
|
2
|
+
|
|
3
|
+
Remove `undefined` values from an object before sending to APIs, databases, or serializers.
|
|
4
|
+
|
|
5
|
+
Zero dependencies. Fully typed. Tiny. Shallow.
|
|
6
|
+
|
|
7
|
+
```ts
|
|
8
|
+
import { stripUndefined } from "strip-undefined-values"
|
|
9
|
+
|
|
10
|
+
stripUndefined({ name: "Tomas", age: undefined, active: true })
|
|
11
|
+
// => { name: "Tomas", active: true }
|
|
12
|
+
```
|
|
13
|
+
|
|
14
|
+
---
|
|
15
|
+
|
|
16
|
+
## Installation
|
|
17
|
+
|
|
18
|
+
```bash
|
|
19
|
+
npm install strip-undefined-values
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
```bash
|
|
23
|
+
pnpm add strip-undefined-values
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
```bash
|
|
27
|
+
yarn add strip-undefined-values
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
---
|
|
31
|
+
|
|
32
|
+
## API
|
|
33
|
+
|
|
34
|
+
```ts
|
|
35
|
+
function stripUndefined<T extends Record<string, any>>(obj: T): StripUndefined<T>
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
Removes own properties whose value is strictly `undefined`.
|
|
39
|
+
Returns a **new object** — does **not** mutate the input.
|
|
40
|
+
Nested objects are not traversed (shallow only).
|
|
41
|
+
|
|
42
|
+
| Value | Kept? |
|
|
43
|
+
| ----------- | ----- |
|
|
44
|
+
| `null` | Yes |
|
|
45
|
+
| `false` | Yes |
|
|
46
|
+
| `0` | Yes |
|
|
47
|
+
| `""` | Yes |
|
|
48
|
+
| `NaN` | Yes |
|
|
49
|
+
| `undefined` | **No**|
|
|
50
|
+
|
|
51
|
+
---
|
|
52
|
+
|
|
53
|
+
## TypeScript
|
|
54
|
+
|
|
55
|
+
The return type `StripUndefined<T>` automatically excludes keys whose type includes `undefined`:
|
|
56
|
+
|
|
57
|
+
```ts
|
|
58
|
+
type Input = { name: string; age: number | undefined; active: boolean }
|
|
59
|
+
type Output = StripUndefined<Input>
|
|
60
|
+
// ^? { name: string; active: boolean }
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
This is intentionally conservative — the type is stricter than runtime so you can never accidentally access a possibly-undefined property on the result.
|
|
64
|
+
|
|
65
|
+
You can also use `StripUndefined<T>` standalone as a utility type:
|
|
66
|
+
|
|
67
|
+
```ts
|
|
68
|
+
import type { StripUndefined } from "strip-undefined-values"
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
---
|
|
72
|
+
|
|
73
|
+
## Common Use Cases
|
|
74
|
+
|
|
75
|
+
### API payloads / PATCH requests
|
|
76
|
+
|
|
77
|
+
```ts
|
|
78
|
+
await fetch("/api/user", {
|
|
79
|
+
method: "PATCH",
|
|
80
|
+
body: JSON.stringify(stripUndefined({ name, email, age }))
|
|
81
|
+
})
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
### Query parameters
|
|
85
|
+
|
|
86
|
+
```ts
|
|
87
|
+
const params = stripUndefined({ page, search, sort })
|
|
88
|
+
const url = `/items?${new URLSearchParams(params)}`
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
### Prisma / database updates
|
|
92
|
+
|
|
93
|
+
```ts
|
|
94
|
+
await prisma.user.update({
|
|
95
|
+
where: { id },
|
|
96
|
+
data: stripUndefined({ name, email, bio })
|
|
97
|
+
})
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
### GraphQL variables
|
|
101
|
+
|
|
102
|
+
```ts
|
|
103
|
+
const { data } = await client.query({
|
|
104
|
+
query: GET_USERS,
|
|
105
|
+
variables: stripUndefined({ first, after, filter })
|
|
106
|
+
})
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
### Optional form fields
|
|
110
|
+
|
|
111
|
+
```ts
|
|
112
|
+
const formData = stripUndefined({
|
|
113
|
+
title: form.title,
|
|
114
|
+
description: form.description || undefined,
|
|
115
|
+
category: form.category || undefined,
|
|
116
|
+
})
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
---
|
|
120
|
+
|
|
121
|
+
## Comparison
|
|
122
|
+
|
|
123
|
+
| Approach | Typed? | Deps | Deep? | Mutates? |
|
|
124
|
+
| --- | --- | --- | --- | --- |
|
|
125
|
+
| **`strip-undefined-values`** | **Yes** | **0** | No | No |
|
|
126
|
+
| `lodash.omitBy` | Partial | 1 | No | No |
|
|
127
|
+
| `Object.fromEntries(…filter…)` | No | 0 | No | No |
|
|
128
|
+
| `remove-undefined-objects` | No | 1+ | Yes | No |
|
|
129
|
+
| Manual `delete` | No | 0 | No | **Yes** |
|
|
130
|
+
|
|
131
|
+
---
|
|
132
|
+
|
|
133
|
+
## License
|
|
134
|
+
|
|
135
|
+
MIT
|
package/dist/index.cjs
ADDED
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.stripUndefined = stripUndefined;
|
|
4
|
+
/**
|
|
5
|
+
* Remove own properties whose value is strictly `undefined` from an object.
|
|
6
|
+
*
|
|
7
|
+
* Returns a **new** plain object — the input is never mutated.
|
|
8
|
+
* Only top-level properties are checked (shallow). Nested objects are
|
|
9
|
+
* copied by reference and left untouched.
|
|
10
|
+
*
|
|
11
|
+
* Values like `null`, `false`, `0`, and `""` are kept.
|
|
12
|
+
*
|
|
13
|
+
* @typeParam T - The source object type
|
|
14
|
+
* @param obj - The object to strip `undefined` values from
|
|
15
|
+
* @returns A new object without any `undefined`-valued properties
|
|
16
|
+
*
|
|
17
|
+
* @example
|
|
18
|
+
* ```ts
|
|
19
|
+
* import { stripUndefined } from "strip-undefined-values"
|
|
20
|
+
*
|
|
21
|
+
* stripUndefined({ name: "Tomas", age: undefined, active: true })
|
|
22
|
+
* // => { name: "Tomas", active: true }
|
|
23
|
+
* ```
|
|
24
|
+
*
|
|
25
|
+
* @example
|
|
26
|
+
* ```ts
|
|
27
|
+
* // Safe for API payloads
|
|
28
|
+
* await fetch("/api/user", {
|
|
29
|
+
* method: "PATCH",
|
|
30
|
+
* body: JSON.stringify(stripUndefined({ name, email, age }))
|
|
31
|
+
* })
|
|
32
|
+
* ```
|
|
33
|
+
*
|
|
34
|
+
* @see {@link StripUndefined} for the companion utility type
|
|
35
|
+
* @since 1.0.0
|
|
36
|
+
*/
|
|
37
|
+
function stripUndefined(obj) {
|
|
38
|
+
const result = {};
|
|
39
|
+
for (const key in obj) {
|
|
40
|
+
if (Object.prototype.hasOwnProperty.call(obj, key)) {
|
|
41
|
+
const value = obj[key];
|
|
42
|
+
if (value !== undefined) {
|
|
43
|
+
result[key] = value;
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
return result;
|
|
48
|
+
}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Mapped type that removes keys whose value type includes `undefined`.
|
|
3
|
+
*
|
|
4
|
+
* @remarks
|
|
5
|
+
* This is intentionally conservative: if a key is typed as `T | undefined`,
|
|
6
|
+
* it is excluded from the result type entirely. At runtime the key is only
|
|
7
|
+
* removed when the value *actually is* `undefined`, so the type is stricter
|
|
8
|
+
* than the runtime behavior. This keeps downstream code safe — you will never
|
|
9
|
+
* accidentally access a possibly-undefined property on the result.
|
|
10
|
+
*
|
|
11
|
+
* @typeParam T - The source object type
|
|
12
|
+
*
|
|
13
|
+
* @example
|
|
14
|
+
* ```ts
|
|
15
|
+
* type Input = { name: string; age: number | undefined }
|
|
16
|
+
* type Output = StripUndefined<Input>
|
|
17
|
+
* // ^? { name: string }
|
|
18
|
+
* ```
|
|
19
|
+
*
|
|
20
|
+
* @since 1.0.0
|
|
21
|
+
*/
|
|
22
|
+
export type StripUndefined<T extends Record<string, any>> = {
|
|
23
|
+
[K in keyof T as undefined extends T[K] ? never : K]: Exclude<T[K], undefined>;
|
|
24
|
+
};
|
|
25
|
+
/**
|
|
26
|
+
* Remove own properties whose value is strictly `undefined` from an object.
|
|
27
|
+
*
|
|
28
|
+
* Returns a **new** plain object — the input is never mutated.
|
|
29
|
+
* Only top-level properties are checked (shallow). Nested objects are
|
|
30
|
+
* copied by reference and left untouched.
|
|
31
|
+
*
|
|
32
|
+
* Values like `null`, `false`, `0`, and `""` are kept.
|
|
33
|
+
*
|
|
34
|
+
* @typeParam T - The source object type
|
|
35
|
+
* @param obj - The object to strip `undefined` values from
|
|
36
|
+
* @returns A new object without any `undefined`-valued properties
|
|
37
|
+
*
|
|
38
|
+
* @example
|
|
39
|
+
* ```ts
|
|
40
|
+
* import { stripUndefined } from "strip-undefined-values"
|
|
41
|
+
*
|
|
42
|
+
* stripUndefined({ name: "Tomas", age: undefined, active: true })
|
|
43
|
+
* // => { name: "Tomas", active: true }
|
|
44
|
+
* ```
|
|
45
|
+
*
|
|
46
|
+
* @example
|
|
47
|
+
* ```ts
|
|
48
|
+
* // Safe for API payloads
|
|
49
|
+
* await fetch("/api/user", {
|
|
50
|
+
* method: "PATCH",
|
|
51
|
+
* body: JSON.stringify(stripUndefined({ name, email, age }))
|
|
52
|
+
* })
|
|
53
|
+
* ```
|
|
54
|
+
*
|
|
55
|
+
* @see {@link StripUndefined} for the companion utility type
|
|
56
|
+
* @since 1.0.0
|
|
57
|
+
*/
|
|
58
|
+
export declare function stripUndefined<T extends Record<string, any>>(obj: T): StripUndefined<T>;
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Remove own properties whose value is strictly `undefined` from an object.
|
|
3
|
+
*
|
|
4
|
+
* Returns a **new** plain object — the input is never mutated.
|
|
5
|
+
* Only top-level properties are checked (shallow). Nested objects are
|
|
6
|
+
* copied by reference and left untouched.
|
|
7
|
+
*
|
|
8
|
+
* Values like `null`, `false`, `0`, and `""` are kept.
|
|
9
|
+
*
|
|
10
|
+
* @typeParam T - The source object type
|
|
11
|
+
* @param obj - The object to strip `undefined` values from
|
|
12
|
+
* @returns A new object without any `undefined`-valued properties
|
|
13
|
+
*
|
|
14
|
+
* @example
|
|
15
|
+
* ```ts
|
|
16
|
+
* import { stripUndefined } from "strip-undefined-values"
|
|
17
|
+
*
|
|
18
|
+
* stripUndefined({ name: "Tomas", age: undefined, active: true })
|
|
19
|
+
* // => { name: "Tomas", active: true }
|
|
20
|
+
* ```
|
|
21
|
+
*
|
|
22
|
+
* @example
|
|
23
|
+
* ```ts
|
|
24
|
+
* // Safe for API payloads
|
|
25
|
+
* await fetch("/api/user", {
|
|
26
|
+
* method: "PATCH",
|
|
27
|
+
* body: JSON.stringify(stripUndefined({ name, email, age }))
|
|
28
|
+
* })
|
|
29
|
+
* ```
|
|
30
|
+
*
|
|
31
|
+
* @see {@link StripUndefined} for the companion utility type
|
|
32
|
+
* @since 1.0.0
|
|
33
|
+
*/
|
|
34
|
+
export function stripUndefined(obj) {
|
|
35
|
+
const result = {};
|
|
36
|
+
for (const key in obj) {
|
|
37
|
+
if (Object.prototype.hasOwnProperty.call(obj, key)) {
|
|
38
|
+
const value = obj[key];
|
|
39
|
+
if (value !== undefined) {
|
|
40
|
+
result[key] = value;
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
return result;
|
|
45
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "strip-undefined-values",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "Remove undefined properties from an object. Fully typed. Zero dependencies.",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "./dist/index.cjs",
|
|
7
|
+
"module": "./dist/index.js",
|
|
8
|
+
"types": "./dist/index.d.ts",
|
|
9
|
+
"exports": {
|
|
10
|
+
".": {
|
|
11
|
+
"types": "./dist/index.d.ts",
|
|
12
|
+
"import": "./dist/index.js",
|
|
13
|
+
"require": "./dist/index.cjs"
|
|
14
|
+
}
|
|
15
|
+
},
|
|
16
|
+
"files": [
|
|
17
|
+
"dist"
|
|
18
|
+
],
|
|
19
|
+
"sideEffects": false,
|
|
20
|
+
"keywords": [
|
|
21
|
+
"strip",
|
|
22
|
+
"undefined",
|
|
23
|
+
"remove undefined",
|
|
24
|
+
"omit undefined",
|
|
25
|
+
"clean object",
|
|
26
|
+
"filter undefined",
|
|
27
|
+
"sanitize object",
|
|
28
|
+
"api payload",
|
|
29
|
+
"typescript",
|
|
30
|
+
"utility",
|
|
31
|
+
"zero-dependency"
|
|
32
|
+
],
|
|
33
|
+
"author": "Tomas",
|
|
34
|
+
"license": "MIT",
|
|
35
|
+
"repository": {
|
|
36
|
+
"type": "git",
|
|
37
|
+
"url": "https://github.com/tomahg/strip-undefined-values"
|
|
38
|
+
},
|
|
39
|
+
"homepage": "https://github.com/tomahg/strip-undefined-values#readme",
|
|
40
|
+
"bugs": {
|
|
41
|
+
"url": "https://github.com/tomahg/strip-undefined-values/issues"
|
|
42
|
+
},
|
|
43
|
+
"engines": {
|
|
44
|
+
"node": ">=14"
|
|
45
|
+
},
|
|
46
|
+
"scripts": {
|
|
47
|
+
"build": "tsc && tsc --module commonjs --outDir dist/cjs --declaration false && node -e \"fs.renameSync('dist/cjs/index.js','dist/index.cjs')\" && node -e \"fs.rmSync('dist/cjs',{recursive:true})\"",
|
|
48
|
+
"clean": "node -e \"fs.rmSync('dist',{recursive:true,force:true})\"",
|
|
49
|
+
"test": "vitest run",
|
|
50
|
+
"test:watch": "vitest",
|
|
51
|
+
"prepublishOnly": "npm run build"
|
|
52
|
+
},
|
|
53
|
+
"devDependencies": {
|
|
54
|
+
"typescript": "^5.0.0",
|
|
55
|
+
"vitest": "^3.0.0"
|
|
56
|
+
}
|
|
57
|
+
}
|