@kakasoo/deep-strict-types 2.0.5 → 2.0.7
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 +173 -260
- package/bin/src/functions/DeepStrictAssert.d.ts +21 -0
- package/bin/src/functions/DeepStrictAssert.d.ts.map +1 -1
- package/bin/src/functions/DeepStrictAssert.js +21 -0
- package/bin/src/functions/DeepStrictAssert.js.map +1 -1
- package/bin/src/functions/DeepStrictObjectKeys.d.ts +27 -0
- package/bin/src/functions/DeepStrictObjectKeys.d.ts.map +1 -1
- package/bin/src/functions/DeepStrictObjectKeys.js +20 -0
- package/bin/src/functions/DeepStrictObjectKeys.js.map +1 -1
- package/bin/src/functions/DeepStrictPick.d.ts +24 -0
- package/bin/src/functions/DeepStrictPick.d.ts.map +1 -0
- package/bin/src/functions/DeepStrictPick.js +53 -0
- package/bin/src/functions/DeepStrictPick.js.map +1 -0
- package/bin/src/functions/index.d.ts +1 -0
- package/bin/src/functions/index.d.ts.map +1 -1
- package/bin/src/functions/index.js +1 -0
- package/bin/src/functions/index.js.map +1 -1
- package/bin/src/types/DeepDateToString.d.ts +22 -4
- package/bin/src/types/DeepDateToString.d.ts.map +1 -1
- package/bin/src/types/DeepStrictMerge.d.ts +11 -0
- package/bin/src/types/DeepStrictMerge.d.ts.map +1 -1
- package/bin/src/types/DeepStrictObjectKeys.d.ts +4 -3
- package/bin/src/types/DeepStrictObjectKeys.d.ts.map +1 -1
- package/bin/src/types/DeepStrictObjectLastKeys.d.ts +18 -3
- package/bin/src/types/DeepStrictObjectLastKeys.d.ts.map +1 -1
- package/bin/src/types/DeepStrictOmit.d.ts +13 -0
- package/bin/src/types/DeepStrictOmit.d.ts.map +1 -1
- package/bin/src/types/DeepStrictUnbrand.d.ts +13 -0
- package/bin/src/types/DeepStrictUnbrand.d.ts.map +1 -1
- package/bin/src/types/Equal.d.ts +7 -4
- package/bin/src/types/Equal.d.ts.map +1 -1
- package/bin/src/types/IsAny.d.ts +11 -6
- package/bin/src/types/IsAny.d.ts.map +1 -1
- package/bin/src/types/RemoveAfterDot.d.ts +22 -0
- package/bin/src/types/RemoveAfterDot.d.ts.map +1 -1
- package/bin/src/types/RemoveArraySymbol.d.ts +16 -4
- package/bin/src/types/RemoveArraySymbol.d.ts.map +1 -1
- package/bin/src/types/RemoveLastProperty.d.ts +21 -0
- package/bin/src/types/RemoveLastProperty.d.ts.map +1 -1
- package/bin/src/types/StringToDeepObject.d.ts +25 -0
- package/bin/src/types/StringToDeepObject.d.ts.map +1 -1
- package/bin/src/types/ValueType.d.ts +17 -0
- package/bin/src/types/ValueType.d.ts.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,362 +1,275 @@
|
|
|
1
|
-
#
|
|
1
|
+
# @kakasoo/deep-strict-types
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
[](https://www.npmjs.com/package/@kakasoo/deep-strict-types)
|
|
4
|
+
[](https://opensource.org/licenses/ISC)
|
|
5
|
+
[](https://www.typescriptlang.org/)
|
|
4
6
|
|
|
5
|
-
|
|
7
|
+
Type-safe `Pick`, `Omit`, and key extraction for deeply nested TypeScript objects and arrays.
|
|
6
8
|
|
|
7
|
-
|
|
8
|
-
2. [DeepStrictObjectKeys](#deepstrictobjectkeys)
|
|
9
|
-
3. [DeepStrictOmit](#deepstrictomit)
|
|
10
|
-
4. [DeepStrictPick](#deepstrictpick)
|
|
11
|
-
5. [StringToDeepObject](#stringtodeepobject)
|
|
12
|
-
6. [DeepStrictMerge](#deepstrictmerge)
|
|
13
|
-
7. [DeepDateToString](#deepdatetostring)
|
|
9
|
+
[한국어 설명](./docs/README_KO.md)
|
|
14
10
|
|
|
15
|
-
|
|
11
|
+

|
|
16
12
|
|
|
17
|
-
|
|
18
|
-
It helps you safely perform tasks like `Omit` and `Pick` even with complex nested objects or arrays.
|
|
19
|
-
By addressing the limitations of TypeScript’s built-in utility types, it allows you to easily handle internal keys with strict and precise type inference.
|
|
13
|
+
## Why in the AI Era?
|
|
20
14
|
|
|
21
|
-
|
|
15
|
+
AI writes more code than ever — and makes more subtle mistakes than ever. This library serves as a **compile-time guardrail** for AI-generated code.
|
|
22
16
|
|
|
23
|
-
|
|
24
|
-
- **Precise Type Manipulation:** You can pick or omit only the keys you need even in deeply nested structures, making it easier to work with complex data.
|
|
25
|
-
- **Unbranding and Merging:** It removes unnecessary constraints from branded types and safely merges multiple types.
|
|
26
|
-
- **Utility Function Support (Experimental):** It even provides runtime functions to further ensure type safety during development.
|
|
17
|
+
### The Problem
|
|
27
18
|
|
|
28
|
-
|
|
19
|
+
AI coding tools often produce code that looks correct but has subtle type mismatches in deeply nested structures:
|
|
29
20
|
|
|
30
|
-
|
|
21
|
+
```typescript
|
|
22
|
+
// AI-generated code: looks fine, but "prce" is a typo
|
|
23
|
+
function getTotal(order: Order) {
|
|
24
|
+
return order.items.map(i => i.prce); // no error with loose types
|
|
25
|
+
}
|
|
26
|
+
```
|
|
31
27
|
|
|
32
|
-
|
|
28
|
+
### The Solution
|
|
33
29
|
|
|
34
|
-
|
|
35
|
-
That means you can access not only top-level keys but also nested keys using dot notation or, for arrays, using `[*]`.
|
|
30
|
+
With strict deep types as constraints, the TypeScript compiler catches AI mistakes **instantly**:
|
|
36
31
|
|
|
37
|
-
|
|
32
|
+
```typescript
|
|
33
|
+
import { DeepStrictPick } from '@kakasoo/deep-strict-types';
|
|
38
34
|
|
|
39
|
-
|
|
40
|
-
- **Accurate Type Inference:** Instead of just using `keyof`, it thoroughly infers every nested key for enhanced type safety.
|
|
41
|
-
- **Array Support:** For objects within arrays, it uses `[*]` instead of an index, so you cover all elements at once.
|
|
35
|
+
type OrderSummary = DeepStrictPick<Order, 'items[*].price' | 'customer.name'>;
|
|
42
36
|
|
|
43
|
-
|
|
37
|
+
// Now AI gets a precise error:
|
|
38
|
+
// Type '"items[*].prce"' is not assignable to
|
|
39
|
+
// type '"items" | "items[*]" | "items[*].price" | "customer" | "customer.name"'
|
|
40
|
+
```
|
|
44
41
|
|
|
45
|
-
|
|
42
|
+
### AI Self-Correction Loop
|
|
46
43
|
|
|
47
|
-
|
|
48
|
-
type Example = {
|
|
49
|
-
user: {
|
|
50
|
-
name: string;
|
|
51
|
-
address: {
|
|
52
|
-
city: string;
|
|
53
|
-
zip: number;
|
|
54
|
-
};
|
|
55
|
-
};
|
|
56
|
-
};
|
|
44
|
+
When used with `tsc` or `tsx` in a build loop, AI agents can read the type error, understand exactly what went wrong, and fix it automatically:
|
|
57
45
|
|
|
58
|
-
|
|
59
|
-
type
|
|
46
|
+
```
|
|
47
|
+
AI generates code → tsc compile → type error → AI reads error → AI self-corrects → recompile
|
|
60
48
|
```
|
|
61
49
|
|
|
62
|
-
The
|
|
50
|
+
The stricter your types, the better the error messages, and the faster AI converges on correct code. **In an AI-driven workflow, deep strict types aren't overhead — they're the safety net.**
|
|
63
51
|
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
52
|
+
## Installation
|
|
53
|
+
|
|
54
|
+
```bash
|
|
55
|
+
npm install @kakasoo/deep-strict-types
|
|
67
56
|
```
|
|
68
57
|
|
|
69
|
-
##
|
|
58
|
+
## Quick Start
|
|
70
59
|
|
|
71
|
-
|
|
72
|
-
|
|
60
|
+
```typescript
|
|
61
|
+
import { DeepStrictObjectKeys, DeepStrictPick, DeepStrictOmit } from '@kakasoo/deep-strict-types';
|
|
73
62
|
|
|
74
|
-
|
|
63
|
+
type User = {
|
|
64
|
+
id: string;
|
|
65
|
+
profile: {
|
|
66
|
+
name: string;
|
|
67
|
+
age: number;
|
|
68
|
+
};
|
|
69
|
+
posts: {
|
|
70
|
+
title: string;
|
|
71
|
+
tags: string[];
|
|
72
|
+
}[];
|
|
73
|
+
};
|
|
75
74
|
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
- **Supports Branded Types:** It works safely with branded types, removing unnecessary constraints.
|
|
75
|
+
// Extract all nested key paths
|
|
76
|
+
type Keys = DeepStrictObjectKeys<User>;
|
|
77
|
+
// "id" | "profile" | "profile.name" | "profile.age" | "posts" | "posts[*].title" | "posts[*].tags"
|
|
80
78
|
|
|
81
|
-
|
|
79
|
+
// Pick only what you need
|
|
80
|
+
type NameOnly = DeepStrictPick<User, 'profile.name'>;
|
|
81
|
+
// { profile: { name: string } }
|
|
82
82
|
|
|
83
|
-
|
|
83
|
+
// Remove what you don't need
|
|
84
|
+
type NoAge = DeepStrictOmit<User, 'profile.age'>;
|
|
85
|
+
// { id: string; profile: { name: string }; posts: { title: string; tags: string[] }[] }
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
## Core Types
|
|
89
|
+
|
|
90
|
+
### `DeepStrictObjectKeys<T>`
|
|
91
|
+
|
|
92
|
+
Extracts all keys from a nested object as a union of dot-notation string paths. Arrays use `[*]` notation.
|
|
84
93
|
|
|
85
94
|
```typescript
|
|
86
|
-
// Define an example object type
|
|
87
95
|
type Example = {
|
|
88
96
|
user: {
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
name: string;
|
|
92
|
-
age: number;
|
|
93
|
-
email: string;
|
|
94
|
-
};
|
|
95
|
-
posts: {
|
|
96
|
-
title: string;
|
|
97
|
-
content: string;
|
|
98
|
-
meta: {
|
|
99
|
-
likes: number;
|
|
100
|
-
shares: number;
|
|
101
|
-
};
|
|
102
|
-
}[];
|
|
97
|
+
name: string;
|
|
98
|
+
address: { city: string; zip: number };
|
|
103
99
|
};
|
|
104
100
|
};
|
|
105
101
|
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
/*
|
|
110
|
-
Resulting type Omitted:
|
|
111
|
-
{
|
|
112
|
-
user: {
|
|
113
|
-
id: string;
|
|
114
|
-
profile: {
|
|
115
|
-
name: string;
|
|
116
|
-
age: number;
|
|
117
|
-
};
|
|
118
|
-
posts: {
|
|
119
|
-
title: string;
|
|
120
|
-
content: string;
|
|
121
|
-
meta: {
|
|
122
|
-
likes: number;
|
|
123
|
-
};
|
|
124
|
-
}[];
|
|
125
|
-
};
|
|
126
|
-
}
|
|
127
|
-
*/
|
|
102
|
+
type Keys = DeepStrictObjectKeys<Example>;
|
|
103
|
+
// "user" | "user.name" | "user.address" | "user.address.city" | "user.address.zip"
|
|
128
104
|
```
|
|
129
105
|
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
## DeepStrictPick
|
|
133
|
-
|
|
134
|
-
`DeepStrictPick` creates a new type by selecting only the specified keys from a nested object type.
|
|
135
|
-
It works like the built-in `Pick` but lets you precisely choose key paths—even in nested structures and arrays—so you only get the properties you need.
|
|
136
|
-
|
|
137
|
-
### Key Features
|
|
106
|
+
```typescript
|
|
107
|
+
type WithArray = { items: { name: string; price: number }[] };
|
|
138
108
|
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
- **Flexible:** You can specify multiple nested keys at once.
|
|
109
|
+
type Keys = DeepStrictObjectKeys<WithArray>;
|
|
110
|
+
// "items" | "items[*].name" | "items[*].price"
|
|
111
|
+
```
|
|
143
112
|
|
|
144
|
-
###
|
|
113
|
+
### `DeepStrictPick<T, K>`
|
|
145
114
|
|
|
146
|
-
|
|
115
|
+
Creates a new type by selecting only the specified nested keys, preserving the object structure.
|
|
147
116
|
|
|
148
117
|
```typescript
|
|
149
|
-
// Define an example object type
|
|
150
118
|
type Example = {
|
|
151
119
|
user: {
|
|
152
120
|
id: string;
|
|
153
|
-
profile: {
|
|
154
|
-
|
|
155
|
-
age: number;
|
|
156
|
-
email: string;
|
|
157
|
-
};
|
|
158
|
-
posts: {
|
|
159
|
-
title: string;
|
|
160
|
-
content: string;
|
|
161
|
-
meta: {
|
|
162
|
-
likes: number;
|
|
163
|
-
shares: number;
|
|
164
|
-
};
|
|
165
|
-
}[];
|
|
121
|
+
profile: { name: string; age: number; email: string };
|
|
122
|
+
posts: { title: string; content: string; meta: { likes: number; shares: number } }[];
|
|
166
123
|
};
|
|
167
124
|
};
|
|
168
125
|
|
|
169
|
-
// Pick only the keys 'user.profile.name' and 'user.posts[*].meta.likes'
|
|
170
126
|
type Picked = DeepStrictPick<Example, 'user.profile.name' | 'user.posts[*].meta.likes'>;
|
|
171
|
-
|
|
172
127
|
/*
|
|
173
|
-
Resulting type Picked:
|
|
174
128
|
{
|
|
175
129
|
user: {
|
|
176
|
-
profile: {
|
|
177
|
-
|
|
178
|
-
};
|
|
179
|
-
posts: {
|
|
180
|
-
meta: {
|
|
181
|
-
likes: number;
|
|
182
|
-
};
|
|
183
|
-
}[];
|
|
130
|
+
profile: { name: string };
|
|
131
|
+
posts: { meta: { likes: number } }[];
|
|
184
132
|
};
|
|
185
133
|
}
|
|
186
134
|
*/
|
|
187
135
|
```
|
|
188
136
|
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
## StringToDeepObject
|
|
192
|
-
|
|
193
|
-
`StringToDeepObject` takes a string path in dot notation and generates a nested object type corresponding to that path.
|
|
194
|
-
It parses the path string step by step, building a nested object and assigning the desired type to the final property.
|
|
137
|
+
### `DeepStrictOmit<T, K>`
|
|
195
138
|
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
- **Parses Path Strings:** Converts a string like "user.profile.name" into an object where each segment becomes a key.
|
|
199
|
-
- **Dynamically Creates Objects:** Automatically builds a nested object based on the path, assigning the specified type at the end.
|
|
200
|
-
- **Merges Union Types:** If you pass a union of path strings, it merges the resulting objects into one combined type.
|
|
201
|
-
- **Type Safe:** Handles string paths safely within the type system to accurately represent nested structures.
|
|
202
|
-
|
|
203
|
-
### Example
|
|
139
|
+
Creates a new type by removing the specified nested keys.
|
|
204
140
|
|
|
205
141
|
```typescript
|
|
206
|
-
|
|
207
|
-
type DeepObj = StringToDeepObject<'user.profile.name', string>;
|
|
208
|
-
|
|
142
|
+
type Omitted = DeepStrictOmit<Example, 'user.profile.email' | 'user.posts[*].meta.shares'>;
|
|
209
143
|
/*
|
|
210
|
-
Resulting type DeepObj:
|
|
211
144
|
{
|
|
212
145
|
user: {
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
};
|
|
146
|
+
id: string;
|
|
147
|
+
profile: { name: string; age: number };
|
|
148
|
+
posts: { title: string; content: string; meta: { likes: number } }[];
|
|
216
149
|
};
|
|
217
150
|
}
|
|
218
151
|
*/
|
|
152
|
+
```
|
|
219
153
|
|
|
220
|
-
|
|
221
|
-
type DeepNumberObj = StringToDeepObject<'settings.display.brightness', number>;
|
|
154
|
+
### `DeepStrictMerge<Target, Source>`
|
|
222
155
|
|
|
223
|
-
|
|
224
|
-
Resulting type DeepNumberObj:
|
|
225
|
-
{
|
|
226
|
-
settings: {
|
|
227
|
-
display: {
|
|
228
|
-
brightness: number;
|
|
229
|
-
};
|
|
230
|
-
};
|
|
231
|
-
}
|
|
232
|
-
*/
|
|
156
|
+
Deeply merges two object types. When both types share a key, `Target` takes precedence.
|
|
233
157
|
|
|
234
|
-
|
|
235
|
-
type
|
|
158
|
+
```typescript
|
|
159
|
+
type A = { user: { id: string; profile: { name: string } } };
|
|
160
|
+
type B = { user: { profile: { email: string }; settings: { theme: string } } };
|
|
236
161
|
|
|
162
|
+
type Merged = DeepStrictMerge<A, B>;
|
|
237
163
|
/*
|
|
238
|
-
Resulting type MergedObj:
|
|
239
164
|
{
|
|
240
165
|
user: {
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
};
|
|
166
|
+
id: string;
|
|
167
|
+
profile: { name: string; email: string };
|
|
168
|
+
settings: { theme: string };
|
|
245
169
|
};
|
|
246
170
|
}
|
|
247
171
|
*/
|
|
248
172
|
```
|
|
249
173
|
|
|
250
|
-
|
|
174
|
+
Arrays of objects are also merged element-wise:
|
|
251
175
|
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
### Key Features
|
|
176
|
+
```typescript
|
|
177
|
+
type Merged = DeepStrictMerge<{ a: number }[], { b: string }[]>;
|
|
178
|
+
// { a: number; b: string }[]
|
|
179
|
+
```
|
|
258
180
|
|
|
259
|
-
|
|
260
|
-
- **Accurate Type Inference:** Each object’s type information is retained in the merged result, ensuring type safety.
|
|
261
|
-
- **Conflict Resolution:** When the same key exists in multiple objects, it resolves the conflict according to defined rules.
|
|
262
|
-
- **Flexible:** You can merge several object types at once, making it easy to manage complex data structures.
|
|
181
|
+
### `GetType<T, K>`
|
|
263
182
|
|
|
264
|
-
|
|
183
|
+
Extracts the type at a specific nested path.
|
|
265
184
|
|
|
266
185
|
```typescript
|
|
267
|
-
|
|
268
|
-
type ObjA = {
|
|
186
|
+
type Data = {
|
|
269
187
|
user: {
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
name: string;
|
|
273
|
-
age: number;
|
|
274
|
-
};
|
|
188
|
+
name: string;
|
|
189
|
+
posts: { title: string; tags: string[] }[];
|
|
275
190
|
};
|
|
276
191
|
};
|
|
277
192
|
|
|
278
|
-
type
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
193
|
+
type T1 = GetType<Data, 'user.name'>; // string
|
|
194
|
+
type T2 = GetType<Data, 'user.posts'>; // { title: string; tags: string[] }[]
|
|
195
|
+
type T3 = GetType<Data, 'user.posts[*].title'>; // string
|
|
196
|
+
type T4 = GetType<Data, 'user.posts[*].tags'>; // string[]
|
|
197
|
+
```
|
|
198
|
+
|
|
199
|
+
### `DeepDateToString<T>`
|
|
200
|
+
|
|
201
|
+
Recursively converts all `Date` types to `string`. Useful for representing serialized/JSON response types.
|
|
202
|
+
|
|
203
|
+
```typescript
|
|
204
|
+
type Input = {
|
|
205
|
+
createdAt: Date;
|
|
206
|
+
user: { name: string; birthDate: Date };
|
|
289
207
|
};
|
|
290
208
|
|
|
291
|
-
|
|
292
|
-
|
|
209
|
+
type Output = DeepDateToString<Input>;
|
|
210
|
+
// { createdAt: string; user: { name: string; birthDate: string } }
|
|
211
|
+
```
|
|
293
212
|
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
};
|
|
307
|
-
};
|
|
308
|
-
}
|
|
309
|
-
*/
|
|
213
|
+
### `DeepStrictUnbrand<T>`
|
|
214
|
+
|
|
215
|
+
Recursively removes branding (e.g., `typia` tags like `Format<'uuid'>`) from types, restoring base primitives.
|
|
216
|
+
|
|
217
|
+
```typescript
|
|
218
|
+
type Branded = {
|
|
219
|
+
id: string & { __brand: 'uuid' };
|
|
220
|
+
profile: { email: string & { __brand: 'email' } };
|
|
221
|
+
};
|
|
222
|
+
|
|
223
|
+
type Clean = DeepStrictUnbrand<Branded>;
|
|
224
|
+
// { id: string; profile: { email: string } }
|
|
310
225
|
```
|
|
311
226
|
|
|
312
|
-
|
|
227
|
+
## Runtime Functions
|
|
313
228
|
|
|
314
|
-
|
|
229
|
+
### `deepStrictObjectKeys(obj)`
|
|
315
230
|
|
|
316
|
-
|
|
317
|
-
It locates all `Date` properties—even deep within nested objects or arrays—and converts them to strings, which is especially useful for serialization or JSON conversion.
|
|
231
|
+
Runtime counterpart of `DeepStrictObjectKeys`. Returns an array of all dot-notation key paths.
|
|
318
232
|
|
|
319
|
-
|
|
233
|
+
```typescript
|
|
234
|
+
import { deepStrictObjectKeys } from '@kakasoo/deep-strict-types';
|
|
235
|
+
|
|
236
|
+
const keys = deepStrictObjectKeys({ a: { b: 1, c: 2 } });
|
|
237
|
+
// ["a", "a.b", "a.c"]
|
|
238
|
+
```
|
|
320
239
|
|
|
321
|
-
|
|
322
|
-
- **Ensures Type Consistency:** By explicitly converting `Date` to `string`, it prevents type mismatches during serialization or API responses.
|
|
323
|
-
- **Handles Complex Structures:** Works reliably even with deeply nested objects and arrays containing `Date` values.
|
|
240
|
+
### `deepStrictAssert(obj)(key)`
|
|
324
241
|
|
|
325
|
-
|
|
242
|
+
Curried runtime function that extracts a specific nested property, preserving the object structure. Type-safe counterpart of `DeepStrictPick`.
|
|
326
243
|
|
|
327
244
|
```typescript
|
|
328
|
-
|
|
329
|
-
type Example = {
|
|
330
|
-
createdAt: Date;
|
|
331
|
-
updatedAt: Date;
|
|
332
|
-
user: {
|
|
333
|
-
name: string;
|
|
334
|
-
birthDate: Date;
|
|
335
|
-
posts: {
|
|
336
|
-
title: string;
|
|
337
|
-
publishedAt: Date;
|
|
338
|
-
}[];
|
|
339
|
-
};
|
|
340
|
-
};
|
|
245
|
+
import { deepStrictAssert } from '@kakasoo/deep-strict-types';
|
|
341
246
|
|
|
342
|
-
|
|
343
|
-
|
|
247
|
+
const data = {
|
|
248
|
+
user: { name: 'Alice', age: 30 },
|
|
249
|
+
posts: [{ title: 'Hello', content: 'World' }],
|
|
250
|
+
};
|
|
344
251
|
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
{
|
|
348
|
-
createdAt: string;
|
|
349
|
-
updatedAt: string;
|
|
350
|
-
user: {
|
|
351
|
-
name: string;
|
|
352
|
-
birthDate: string;
|
|
353
|
-
posts: {
|
|
354
|
-
title: string;
|
|
355
|
-
publishedAt: string;
|
|
356
|
-
}[];
|
|
357
|
-
};
|
|
358
|
-
}
|
|
359
|
-
*/
|
|
252
|
+
const result = deepStrictAssert(data)('user.name');
|
|
253
|
+
// { user: { name: 'Alice' } }
|
|
360
254
|
```
|
|
361
255
|
|
|
362
|
-
|
|
256
|
+
## Utility Types
|
|
257
|
+
|
|
258
|
+
| Type | Description | Example |
|
|
259
|
+
|------|-------------|---------|
|
|
260
|
+
| `DeepStrictObjectLastKeys<T>` | Extracts only the leaf-level (deepest) keys | `"a.b.c"` instead of `"a" \| "a.b" \| "a.b.c"` |
|
|
261
|
+
| `StringToDeepObject<T>` | Converts a comma-separated dot-notation string to a nested object type | `StringToDeepObject<"a.b,c">` = `{ a: { b: any }; c: any }` |
|
|
262
|
+
| `Equal<X, Y>` | Type-level equality check (returns `true` or `false`) | `Equal<string, string>` = `true` |
|
|
263
|
+
| `ElementOf<T>` | Extracts the element type from an array | `ElementOf<string[]>` = `string` |
|
|
264
|
+
| `IsAny<T>` | Checks if a type is `any` | `IsAny<any>` = `true` |
|
|
265
|
+
| `IsUnion<T>` | Checks if a type is a union | `IsUnion<string \| number>` = `true` |
|
|
266
|
+
| `ValueType` | Union of all primitive types + `Date` | `string \| number \| boolean \| ...` |
|
|
267
|
+
| `GetMember<T, Prefix>` | Extracts key segments after a dot-notation prefix | Internal helper for `DeepStrictOmit` |
|
|
268
|
+
| `GetElementMember<T, Prefix>` | Extracts array element sub-keys after a `[*]` prefix | Internal helper for `DeepStrictOmit` |
|
|
269
|
+
| `RemoveAfterDot<T, K>` | Generates wildcard patterns for descendant keys | Internal helper for `DeepStrictPick` |
|
|
270
|
+
| `RemoveArraySymbol<T>` | Strips `[*]` suffix from a key string | `RemoveArraySymbol<"items[*]">` = `"items"` |
|
|
271
|
+
| `RemoveLastProperty<T>` | Extracts all parent path segments | `RemoveLastProperty<"a.b.c">` = `"a" \| "a.b"` |
|
|
272
|
+
|
|
273
|
+
## License
|
|
274
|
+
|
|
275
|
+
ISC
|
|
@@ -1,4 +1,25 @@
|
|
|
1
1
|
import { DeepStrictObjectKeys } from '../types/DeepStrictObjectKeys';
|
|
2
2
|
import { DeepStrictPick } from '../types/DeepStrictPick';
|
|
3
|
+
/**
|
|
4
|
+
* @title Runtime Function for Type-Safe Deep Property Extraction.
|
|
5
|
+
*
|
|
6
|
+
* A curried function that takes an object and returns a picker function.
|
|
7
|
+
* The picker function accepts a dot-notation key path and returns a new object
|
|
8
|
+
* containing only the specified nested property, preserving the original structure.
|
|
9
|
+
*
|
|
10
|
+
* This is the runtime counterpart of the {@link DeepStrictPick} type.
|
|
11
|
+
*
|
|
12
|
+
* @deprecated Use {@link deepStrictPick} instead. This curried form will be removed in a future version.
|
|
13
|
+
*
|
|
14
|
+
* @template T - The object type of the input
|
|
15
|
+
* @param input - The source object to extract properties from
|
|
16
|
+
* @returns A function that accepts a key path `K` and returns the deeply-picked result
|
|
17
|
+
*
|
|
18
|
+
* @example
|
|
19
|
+
* ```ts
|
|
20
|
+
* const result = deepStrictAssert({ a: { b: 1, c: 2 } })('a.b');
|
|
21
|
+
* // result: { a: { b: 1 } }
|
|
22
|
+
* ```
|
|
23
|
+
*/
|
|
3
24
|
export declare const deepStrictAssert: <T extends object>(input: T) => <K extends DeepStrictObjectKeys<T>>(key: K) => DeepStrictPick<T, K>;
|
|
4
25
|
//# sourceMappingURL=DeepStrictAssert.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"DeepStrictAssert.d.ts","sourceRoot":"","sources":["../../../src/functions/DeepStrictAssert.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,oBAAoB,EAAE,MAAM,+BAA+B,CAAC;AACrE,OAAO,EAAE,cAAc,EAAE,MAAM,yBAAyB,CAAC;AAEzD,eAAO,MAAM,gBAAgB,GAC1B,CAAC,SAAS,MAAM,SAAS,CAAC,MAC1B,CAAC,SAAS,oBAAoB,CAAC,CAAC,CAAC,OAAO,CAAC,KAAG,cAAc,CAAC,CAAC,EAAE,CAAC,CAiC/D,CAAC"}
|
|
1
|
+
{"version":3,"file":"DeepStrictAssert.d.ts","sourceRoot":"","sources":["../../../src/functions/DeepStrictAssert.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,oBAAoB,EAAE,MAAM,+BAA+B,CAAC;AACrE,OAAO,EAAE,cAAc,EAAE,MAAM,yBAAyB,CAAC;AAEzD;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,eAAO,MAAM,gBAAgB,GAC1B,CAAC,SAAS,MAAM,SAAS,CAAC,MAC1B,CAAC,SAAS,oBAAoB,CAAC,CAAC,CAAC,OAAO,CAAC,KAAG,cAAc,CAAC,CAAC,EAAE,CAAC,CAiC/D,CAAC"}
|
|
@@ -1,6 +1,27 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.deepStrictAssert = void 0;
|
|
4
|
+
/**
|
|
5
|
+
* @title Runtime Function for Type-Safe Deep Property Extraction.
|
|
6
|
+
*
|
|
7
|
+
* A curried function that takes an object and returns a picker function.
|
|
8
|
+
* The picker function accepts a dot-notation key path and returns a new object
|
|
9
|
+
* containing only the specified nested property, preserving the original structure.
|
|
10
|
+
*
|
|
11
|
+
* This is the runtime counterpart of the {@link DeepStrictPick} type.
|
|
12
|
+
*
|
|
13
|
+
* @deprecated Use {@link deepStrictPick} instead. This curried form will be removed in a future version.
|
|
14
|
+
*
|
|
15
|
+
* @template T - The object type of the input
|
|
16
|
+
* @param input - The source object to extract properties from
|
|
17
|
+
* @returns A function that accepts a key path `K` and returns the deeply-picked result
|
|
18
|
+
*
|
|
19
|
+
* @example
|
|
20
|
+
* ```ts
|
|
21
|
+
* const result = deepStrictAssert({ a: { b: 1, c: 2 } })('a.b');
|
|
22
|
+
* // result: { a: { b: 1 } }
|
|
23
|
+
* ```
|
|
24
|
+
*/
|
|
4
25
|
const deepStrictAssert = (input) => (key) => {
|
|
5
26
|
const keys = key.split(/(?:\[\*\])?\./g).filter(Boolean);
|
|
6
27
|
const traverse = (input, keys) => {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"DeepStrictAssert.js","sourceRoot":"","sources":["../../../src/functions/DeepStrictAssert.ts"],"names":[],"mappings":";;;
|
|
1
|
+
{"version":3,"file":"DeepStrictAssert.js","sourceRoot":"","sources":["../../../src/functions/DeepStrictAssert.ts"],"names":[],"mappings":";;;AAGA;;;;;;;;;;;;;;;;;;;;GAoBG;AACI,MAAM,gBAAgB,GAC3B,CAAmB,KAAQ,EAAE,EAAE,CAC/B,CAAoC,GAAM,EAAwB,EAAE;IAClE,MAAM,IAAI,GAAG,GAAG,CAAC,KAAK,CAAC,gBAAgB,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;IAEzD,MAAM,QAAQ,GAAG,CAAC,KAAkD,EAAE,IAAc,EAAO,EAAE;QAC3F,MAAM,CAAC,KAAK,EAAE,GAAG,IAAI,CAAC,GAAG,IAAI,CAAC;QAE9B,IAAI,KAAK,YAAY,KAAK,EAAE,CAAC;YAC3B,MAAM,QAAQ,GAAG,KAAK,CAAC,GAAG,CAAC,CAAC,OAAO,EAAE,EAAE;gBACrC,IAAI,KAAK,IAAI,OAAO,EAAE,CAAC;oBACrB,IAAI,OAAO,OAAO,CAAC,KAAK,CAAC,KAAK,QAAQ,IAAI,OAAO,CAAC,KAAK,CAAC,KAAK,IAAI,EAAE,CAAC;wBAClE,OAAO,EAAE,CAAC,KAAK,CAAC,EAAE,QAAQ,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,IAAI,CAAC,EAAE,CAAC;oBACrD,CAAC;oBAED,OAAO,EAAE,CAAC,KAAK,CAAC,EAAE,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC;gBACrC,CAAC;gBAED,OAAO,OAAO,CAAC;YACjB,CAAC,CAAC,CAAC;YAEH,OAAO,QAAQ,CAAC;QAClB,CAAC;aAAM,CAAC;YACN,IAAI,KAAK,IAAI,KAAK,EAAE,CAAC;gBACnB,IAAI,OAAO,KAAK,CAAC,KAAK,CAAC,KAAK,QAAQ,IAAI,KAAK,CAAC,KAAK,CAAC,KAAK,IAAI,EAAE,CAAC;oBAC9D,OAAO,EAAE,CAAC,KAAK,CAAC,EAAE,QAAQ,CAAC,KAAK,CAAC,KAAK,CAAC,EAAE,IAAI,CAAC,EAAE,CAAC;gBACnD,CAAC;gBACD,OAAO,EAAE,CAAC,KAAK,CAAC,EAAE,KAAK,CAAC,KAAK,CAAC,EAAE,CAAC;YACnC,CAAC;YAED,MAAM,IAAI,KAAK,CAAC,2BAA2B,KAAK,EAAE,CAAC,CAAC;QACtD,CAAC;IACH,CAAC,CAAC;IAEF,OAAO,QAAQ,CAAC,KAAK,EAAE,IAAI,CAAyB,CAAC;AACvD,CAAC,CAAC;AAnCS,QAAA,gBAAgB,oBAmCzB"}
|
|
@@ -1,6 +1,13 @@
|
|
|
1
1
|
import { DeepStrictObjectKeys } from '../types';
|
|
2
|
+
/** @internal Removes a leading dot from a string type. e.g., `".foo"` becomes `"foo"`. */
|
|
2
3
|
type RemoveStartWithDot<T extends string> = T extends `.${infer R extends string}` ? R : T;
|
|
4
|
+
/** @internal Replaces all `[*]` array notation with `${number}` for runtime key path access. */
|
|
3
5
|
type Replace<S extends string> = S extends '[*]' ? `${number}` : S extends `[*].${infer Rest}` ? `${number}.${Replace<Rest>}` : S extends `${infer Prefix extends string}.[*]${infer Rest}` ? `${Prefix}.${number}${Replace<Rest>}` : S extends `${infer Prefix extends string}[*]${infer Rest}` ? `${Prefix}.${number}${Replace<Rest>}` : S;
|
|
6
|
+
/**
|
|
7
|
+
* @internal The return type for {@link deepStrictObjectKeys}.
|
|
8
|
+
* Converts type-level keys (with `[*]` notation) to runtime-friendly keys (with `${number}` notation),
|
|
9
|
+
* strips leading dots, and wraps the result in an array type.
|
|
10
|
+
*/
|
|
4
11
|
type ReturnType<Target extends object, Joiner extends {
|
|
5
12
|
array: string;
|
|
6
13
|
object: string;
|
|
@@ -8,6 +15,26 @@ type ReturnType<Target extends object, Joiner extends {
|
|
|
8
15
|
array: '[*]';
|
|
9
16
|
object: '.';
|
|
10
17
|
}> = [Target] extends [never] ? [] : RemoveStartWithDot<Replace<DeepStrictObjectKeys<Target, Joiner, false>>>[];
|
|
18
|
+
/**
|
|
19
|
+
* @title Runtime Function for Extracting All Nested Keys from an Object.
|
|
20
|
+
*
|
|
21
|
+
* Recursively traverses the input object and returns a flat array of all key paths
|
|
22
|
+
* using dot notation. Nested objects produce paths like `"a.b.c"`, and arrays produce
|
|
23
|
+
* indexed paths at runtime.
|
|
24
|
+
*
|
|
25
|
+
* This is the runtime counterpart of the {@link DeepStrictObjectKeys} type.
|
|
26
|
+
*
|
|
27
|
+
* @template Target - The object type to extract keys from
|
|
28
|
+
* @template Joiner - Separator symbols (defaults to `{ array: '[*]', object: '.' }`)
|
|
29
|
+
* @param target - The object instance to extract keys from
|
|
30
|
+
* @returns An array of all dot-notation key paths in the object
|
|
31
|
+
*
|
|
32
|
+
* @example
|
|
33
|
+
* ```ts
|
|
34
|
+
* const keys = deepStrictObjectKeys({ a: { b: 1, c: 2 } });
|
|
35
|
+
* // keys: ["a", "a.b", "a.c"]
|
|
36
|
+
* ```
|
|
37
|
+
*/
|
|
11
38
|
export declare function deepStrictObjectKeys<Target extends object, Joiner extends {
|
|
12
39
|
array: string;
|
|
13
40
|
object: string;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"DeepStrictObjectKeys.d.ts","sourceRoot":"","sources":["../../../src/functions/DeepStrictObjectKeys.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,oBAAoB,EAAE,MAAM,UAAU,CAAC;AAEhD,KAAK,kBAAkB,CAAC,CAAC,SAAS,MAAM,IAAI,CAAC,SAAS,IAAI,MAAM,CAAC,SAAS,MAAM,EAAE,GAAG,CAAC,GAAG,CAAC,CAAC;AAE3F,KAAK,OAAO,CAAC,CAAC,SAAS,MAAM,IAAI,CAAC,SAAS,KAAK,GAC5C,GAAG,MAAM,EAAE,GACX,CAAC,SAAS,OAAO,MAAM,IAAI,EAAE,GAC3B,GAAG,MAAM,IAAI,OAAO,CAAC,IAAI,CAAC,EAAE,GAC5B,CAAC,SAAS,GAAG,MAAM,MAAM,SAAS,MAAM,OAAO,MAAM,IAAI,EAAE,GACzD,GAAG,MAAM,IAAI,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,EAAE,GACrC,CAAC,SAAS,GAAG,MAAM,MAAM,SAAS,MAAM,MAAM,MAAM,IAAI,EAAE,GACxD,GAAG,MAAM,IAAI,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,EAAE,GACrC,CAAC,CAAC;AAEZ,KAAK,UAAU,CACb,MAAM,SAAS,MAAM,EACrB,MAAM,SAAS;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,GAAG;IAAE,KAAK,EAAE,KAAK,CAAC;IAAC,MAAM,EAAE,GAAG,CAAA;CAAE,IAC9E,CAAC,MAAM,CAAC,SAAS,CAAC,KAAK,CAAC,GAAG,EAAE,GAAG,kBAAkB,CAAC,OAAO,CAAC,oBAAoB,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,CAAC,CAAC,CAAC,EAAE,CAAC;AAE/G,wBAAgB,oBAAoB,CAClC,MAAM,SAAS,MAAM,EACrB,MAAM,SAAS;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,GAAG;IAAE,KAAK,EAAE,KAAK,CAAC;IAAC,MAAM,EAAE,GAAG,CAAA;CAAE,EAChF,MAAM,EAAE,MAAM,GAAG,UAAU,CAAC,MAAM,EAAE,MAAM,CAAC,CAqB5C"}
|
|
1
|
+
{"version":3,"file":"DeepStrictObjectKeys.d.ts","sourceRoot":"","sources":["../../../src/functions/DeepStrictObjectKeys.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,oBAAoB,EAAE,MAAM,UAAU,CAAC;AAEhD,0FAA0F;AAC1F,KAAK,kBAAkB,CAAC,CAAC,SAAS,MAAM,IAAI,CAAC,SAAS,IAAI,MAAM,CAAC,SAAS,MAAM,EAAE,GAAG,CAAC,GAAG,CAAC,CAAC;AAE3F,gGAAgG;AAChG,KAAK,OAAO,CAAC,CAAC,SAAS,MAAM,IAAI,CAAC,SAAS,KAAK,GAC5C,GAAG,MAAM,EAAE,GACX,CAAC,SAAS,OAAO,MAAM,IAAI,EAAE,GAC3B,GAAG,MAAM,IAAI,OAAO,CAAC,IAAI,CAAC,EAAE,GAC5B,CAAC,SAAS,GAAG,MAAM,MAAM,SAAS,MAAM,OAAO,MAAM,IAAI,EAAE,GACzD,GAAG,MAAM,IAAI,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,EAAE,GACrC,CAAC,SAAS,GAAG,MAAM,MAAM,SAAS,MAAM,MAAM,MAAM,IAAI,EAAE,GACxD,GAAG,MAAM,IAAI,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,EAAE,GACrC,CAAC,CAAC;AAEZ;;;;GAIG;AACH,KAAK,UAAU,CACb,MAAM,SAAS,MAAM,EACrB,MAAM,SAAS;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,GAAG;IAAE,KAAK,EAAE,KAAK,CAAC;IAAC,MAAM,EAAE,GAAG,CAAA;CAAE,IAC9E,CAAC,MAAM,CAAC,SAAS,CAAC,KAAK,CAAC,GAAG,EAAE,GAAG,kBAAkB,CAAC,OAAO,CAAC,oBAAoB,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,CAAC,CAAC,CAAC,EAAE,CAAC;AAE/G;;;;;;;;;;;;;;;;;;;GAmBG;AACH,wBAAgB,oBAAoB,CAClC,MAAM,SAAS,MAAM,EACrB,MAAM,SAAS;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,GAAG;IAAE,KAAK,EAAE,KAAK,CAAC;IAAC,MAAM,EAAE,GAAG,CAAA;CAAE,EAChF,MAAM,EAAE,MAAM,GAAG,UAAU,CAAC,MAAM,EAAE,MAAM,CAAC,CAqB5C"}
|