0
# Object Utilities
1
2
Object manipulation helpers for property access, copying, transformation, and introspection operations in JavaScript/TypeScript applications.
3
4
## Capabilities
5
6
### Object Property Access
7
8
Functions for accessing and manipulating object properties with type safety.
9
10
```typescript { .api }
11
/**
12
* Gets all keys from an object with proper typing
13
* @param value - Object to get keys from
14
*/
15
function objectKeys<T>(value: T): (keyof T)[];
16
17
/**
18
* Gets all values from an object
19
* @param value - Object to get values from
20
*/
21
function objectValues<T>(value: T): T[keyof T][];
22
23
/**
24
* Gets key-value pairs from an object as tuples
25
* @param value - Object to get entries from
26
*/
27
function objectEntries<T>(value: T): [keyof T, T[keyof T]][];
28
```
29
30
### Object Manipulation
31
32
Core functions for copying, spreading, and clearing objects.
33
34
```typescript { .api }
35
/**
36
* Creates a shallow copy of an object
37
* @param source - Object to copy
38
*/
39
function objectCopy<T>(source: T): T;
40
41
/**
42
* Spreads properties from source objects to destination
43
* @param dest - Destination object
44
* @param sources - Source objects to spread from
45
*/
46
function objectSpread<T, S>(dest: T, ...sources: S[]): T & S;
47
48
/**
49
* Clears all properties from an object
50
* @param value - Object to clear
51
*/
52
function objectClear(value: Record<string, unknown>): Record<string, unknown>;
53
```
54
55
### Property Introspection
56
57
Advanced functions for examining object property descriptors.
58
59
```typescript { .api }
60
/**
61
* Gets property descriptors for all properties
62
* @param value - Object to examine
63
*/
64
function objectProperties(value: Record<string, unknown>): Record<string, PropertyDescriptor>;
65
66
/**
67
* Gets property descriptor for a single property
68
* @param value - Object to examine
69
* @param property - Property name to get descriptor for
70
*/
71
function objectProperty(value: Record<string, unknown>, property: string): PropertyDescriptor | undefined;
72
```
73
74
## Usage Examples
75
76
**Object Property Access:**
77
78
```typescript
79
import { objectKeys, objectValues, objectEntries } from "@polkadot/util";
80
81
const user = {
82
id: 123,
83
name: "Alice",
84
email: "alice@example.com",
85
active: true
86
};
87
88
// Get typed keys
89
const keys = objectKeys(user); // ("id" | "name" | "email" | "active")[]
90
console.log(keys); // ["id", "name", "email", "active"]
91
92
// Get all values
93
const values = objectValues(user); // (string | number | boolean)[]
94
console.log(values); // [123, "Alice", "alice@example.com", true]
95
96
// Get key-value pairs
97
const entries = objectEntries(user);
98
console.log(entries);
99
// [["id", 123], ["name", "Alice"], ["email", "alice@example.com"], ["active", true]]
100
101
// Use entries for transformation
102
const uppercaseKeys = Object.fromEntries(
103
entries.map(([key, value]) => [key.toUpperCase(), value])
104
);
105
console.log(uppercaseKeys); // { ID: 123, NAME: "Alice", ... }
106
```
107
108
**Object Copying and Spreading:**
109
110
```typescript
111
import { objectCopy, objectSpread } from "@polkadot/util";
112
113
const original = { name: "John", age: 30 };
114
115
// Create shallow copy
116
const copy = objectCopy(original);
117
copy.age = 31; // Doesn't affect original
118
console.log(original.age); // 30
119
console.log(copy.age); // 31
120
121
// Spread properties into new object
122
const defaults = { theme: "dark", notifications: true };
123
const userPrefs = { theme: "light" };
124
const final = objectSpread({}, defaults, userPrefs);
125
console.log(final); // { theme: "light", notifications: true }
126
127
// Spread into existing object
128
const target = { id: 1 };
129
const result = objectSpread(target, { name: "Alice" }, { active: true });
130
console.log(result); // { id: 1, name: "Alice", active: true }
131
console.log(target === result); // true (modified in-place)
132
```
133
134
**Configuration Merging:**
135
136
```typescript
137
import { objectSpread, objectCopy } from "@polkadot/util";
138
139
// Merge configuration objects
140
function createConfig(userConfig: Partial<Config> = {}): Config {
141
const defaultConfig = {
142
apiUrl: "https://api.example.com",
143
timeout: 5000,
144
retries: 3,
145
debug: false
146
};
147
148
return objectSpread(objectCopy(defaultConfig), userConfig);
149
}
150
151
interface Config {
152
apiUrl: string;
153
timeout: number;
154
retries: number;
155
debug: boolean;
156
}
157
158
const config1 = createConfig(); // Uses all defaults
159
const config2 = createConfig({ debug: true, timeout: 10000 }); // Override specific values
160
161
console.log(config1.debug); // false
162
console.log(config2.debug); // true
163
console.log(config2.apiUrl); // "https://api.example.com" (from defaults)
164
```
165
166
**Object Clearing:**
167
168
```typescript
169
import { objectClear } from "@polkadot/util";
170
171
// Clear object while preserving reference
172
const cache = { user123: { name: "Alice" }, user456: { name: "Bob" } };
173
const originalRef = cache;
174
175
objectClear(cache);
176
console.log(cache); // {}
177
console.log(originalRef === cache); // true (same reference)
178
179
// Useful for resetting state
180
class StateManager {
181
private state: Record<string, unknown> = {};
182
183
setState(newState: Record<string, unknown>) {
184
objectClear(this.state);
185
objectSpread(this.state, newState);
186
}
187
188
clearState() {
189
objectClear(this.state);
190
}
191
192
getState() {
193
return this.state;
194
}
195
}
196
```
197
198
**Property Introspection:**
199
200
```typescript
201
import { objectProperties, objectProperty } from "@polkadot/util";
202
203
class Example {
204
public name = "test";
205
private _id = 123;
206
207
get id() { return this._id; }
208
set id(value: number) { this._id = value; }
209
210
method() { return "hello"; }
211
}
212
213
const instance = new Example();
214
215
// Get all property descriptors
216
const allProps = objectProperties(instance);
217
console.log(Object.keys(allProps)); // ["name", "_id", "id", "method", ...]
218
219
// Get specific property descriptor
220
const nameDesc = objectProperty(instance, "name");
221
console.log(nameDesc?.writable); // true
222
console.log(nameDesc?.enumerable); // true
223
224
const idDesc = objectProperty(instance, "id");
225
console.log(idDesc?.get); // [Function: get id]
226
console.log(idDesc?.set); // [Function: set id]
227
228
// Check if property is configurable
229
function isConfigurableProperty(obj: Record<string, unknown>, prop: string): boolean {
230
const desc = objectProperty(obj, prop);
231
return desc?.configurable === true;
232
}
233
```
234
235
**Data Transformation Pipeline:**
236
237
```typescript
238
import { objectEntries, objectKeys, objectSpread } from "@polkadot/util";
239
240
// Transform object keys and values
241
function transformObject<T extends Record<string, unknown>>(
242
obj: T,
243
keyTransform: (key: string) => string,
244
valueTransform: (value: unknown, key: string) => unknown
245
): Record<string, unknown> {
246
return Object.fromEntries(
247
objectEntries(obj).map(([key, value]) => [
248
keyTransform(String(key)),
249
valueTransform(value, String(key))
250
])
251
);
252
}
253
254
// Example: Convert API response to internal format
255
const apiResponse = {
256
"user_id": "123",
257
"full_name": "John Doe",
258
"email_address": "john@example.com",
259
"is_active": "true",
260
"created_at": "2023-01-01T00:00:00Z"
261
};
262
263
const internal = transformObject(
264
apiResponse,
265
key => key.replace(/_([a-z])/g, (_, letter) => letter.toUpperCase()), // snake_case to camelCase
266
(value, key) => {
267
if (key.includes('is_') && typeof value === 'string') {
268
return value === 'true'; // Convert string booleans
269
}
270
if (key.includes('_at') && typeof value === 'string') {
271
return new Date(value); // Convert date strings
272
}
273
return value;
274
}
275
);
276
277
console.log(internal);
278
// {
279
// userId: "123",
280
// fullName: "John Doe",
281
// emailAddress: "john@example.com",
282
// isActive: true,
283
// createdAt: Date object
284
// }
285
```
286
287
**Object Validation:**
288
289
```typescript
290
import { objectKeys, objectEntries } from "@polkadot/util";
291
292
// Validate object structure
293
function validateObjectStructure<T extends Record<string, unknown>>(
294
obj: unknown,
295
requiredKeys: (keyof T)[],
296
optionalKeys: (keyof T)[] = []
297
): obj is T {
298
if (!obj || typeof obj !== 'object') return false;
299
300
const keys = objectKeys(obj as Record<string, unknown>);
301
const allowedKeys = [...requiredKeys, ...optionalKeys];
302
303
// Check all required keys exist
304
const hasAllRequired = requiredKeys.every(key => keys.includes(key as string));
305
306
// Check no extra keys exist
307
const hasOnlyAllowed = keys.every(key => allowedKeys.includes(key as keyof T));
308
309
return hasAllRequired && hasOnlyAllowed;
310
}
311
312
interface User {
313
id: number;
314
name: string;
315
email?: string;
316
}
317
318
const validUser = { id: 123, name: "Alice", email: "alice@example.com" };
319
const invalidUser = { id: 123, extra: "field" }; // Missing required 'name'
320
321
console.log(validateObjectStructure<User>(validUser, ['id', 'name'], ['email'])); // true
322
console.log(validateObjectStructure<User>(invalidUser, ['id', 'name'], ['email'])); // false
323
```