A collection of useful utilities for @polkadot ecosystem with type checking, data conversion, and performance optimization functions
—
Quality
Pending
Does it follow best practices?
Impact
Pending
No eval scenarios have been run
Object manipulation helpers for property access, copying, transformation, and introspection operations in JavaScript/TypeScript applications.
Functions for accessing and manipulating object properties with type safety.
/**
* Gets all keys from an object with proper typing
* @param value - Object to get keys from
*/
function objectKeys<T>(value: T): (keyof T)[];
/**
* Gets all values from an object
* @param value - Object to get values from
*/
function objectValues<T>(value: T): T[keyof T][];
/**
* Gets key-value pairs from an object as tuples
* @param value - Object to get entries from
*/
function objectEntries<T>(value: T): [keyof T, T[keyof T]][];Core functions for copying, spreading, and clearing objects.
/**
* Creates a shallow copy of an object
* @param source - Object to copy
*/
function objectCopy<T>(source: T): T;
/**
* Spreads properties from source objects to destination
* @param dest - Destination object
* @param sources - Source objects to spread from
*/
function objectSpread<T, S>(dest: T, ...sources: S[]): T & S;
/**
* Clears all properties from an object
* @param value - Object to clear
*/
function objectClear(value: Record<string, unknown>): Record<string, unknown>;Advanced functions for examining object property descriptors.
/**
* Gets property descriptors for all properties
* @param value - Object to examine
*/
function objectProperties(value: Record<string, unknown>): Record<string, PropertyDescriptor>;
/**
* Gets property descriptor for a single property
* @param value - Object to examine
* @param property - Property name to get descriptor for
*/
function objectProperty(value: Record<string, unknown>, property: string): PropertyDescriptor | undefined;Object Property Access:
import { objectKeys, objectValues, objectEntries } from "@polkadot/util";
const user = {
id: 123,
name: "Alice",
email: "alice@example.com",
active: true
};
// Get typed keys
const keys = objectKeys(user); // ("id" | "name" | "email" | "active")[]
console.log(keys); // ["id", "name", "email", "active"]
// Get all values
const values = objectValues(user); // (string | number | boolean)[]
console.log(values); // [123, "Alice", "alice@example.com", true]
// Get key-value pairs
const entries = objectEntries(user);
console.log(entries);
// [["id", 123], ["name", "Alice"], ["email", "alice@example.com"], ["active", true]]
// Use entries for transformation
const uppercaseKeys = Object.fromEntries(
entries.map(([key, value]) => [key.toUpperCase(), value])
);
console.log(uppercaseKeys); // { ID: 123, NAME: "Alice", ... }Object Copying and Spreading:
import { objectCopy, objectSpread } from "@polkadot/util";
const original = { name: "John", age: 30 };
// Create shallow copy
const copy = objectCopy(original);
copy.age = 31; // Doesn't affect original
console.log(original.age); // 30
console.log(copy.age); // 31
// Spread properties into new object
const defaults = { theme: "dark", notifications: true };
const userPrefs = { theme: "light" };
const final = objectSpread({}, defaults, userPrefs);
console.log(final); // { theme: "light", notifications: true }
// Spread into existing object
const target = { id: 1 };
const result = objectSpread(target, { name: "Alice" }, { active: true });
console.log(result); // { id: 1, name: "Alice", active: true }
console.log(target === result); // true (modified in-place)Configuration Merging:
import { objectSpread, objectCopy } from "@polkadot/util";
// Merge configuration objects
function createConfig(userConfig: Partial<Config> = {}): Config {
const defaultConfig = {
apiUrl: "https://api.example.com",
timeout: 5000,
retries: 3,
debug: false
};
return objectSpread(objectCopy(defaultConfig), userConfig);
}
interface Config {
apiUrl: string;
timeout: number;
retries: number;
debug: boolean;
}
const config1 = createConfig(); // Uses all defaults
const config2 = createConfig({ debug: true, timeout: 10000 }); // Override specific values
console.log(config1.debug); // false
console.log(config2.debug); // true
console.log(config2.apiUrl); // "https://api.example.com" (from defaults)Object Clearing:
import { objectClear } from "@polkadot/util";
// Clear object while preserving reference
const cache = { user123: { name: "Alice" }, user456: { name: "Bob" } };
const originalRef = cache;
objectClear(cache);
console.log(cache); // {}
console.log(originalRef === cache); // true (same reference)
// Useful for resetting state
class StateManager {
private state: Record<string, unknown> = {};
setState(newState: Record<string, unknown>) {
objectClear(this.state);
objectSpread(this.state, newState);
}
clearState() {
objectClear(this.state);
}
getState() {
return this.state;
}
}Property Introspection:
import { objectProperties, objectProperty } from "@polkadot/util";
class Example {
public name = "test";
private _id = 123;
get id() { return this._id; }
set id(value: number) { this._id = value; }
method() { return "hello"; }
}
const instance = new Example();
// Get all property descriptors
const allProps = objectProperties(instance);
console.log(Object.keys(allProps)); // ["name", "_id", "id", "method", ...]
// Get specific property descriptor
const nameDesc = objectProperty(instance, "name");
console.log(nameDesc?.writable); // true
console.log(nameDesc?.enumerable); // true
const idDesc = objectProperty(instance, "id");
console.log(idDesc?.get); // [Function: get id]
console.log(idDesc?.set); // [Function: set id]
// Check if property is configurable
function isConfigurableProperty(obj: Record<string, unknown>, prop: string): boolean {
const desc = objectProperty(obj, prop);
return desc?.configurable === true;
}Data Transformation Pipeline:
import { objectEntries, objectKeys, objectSpread } from "@polkadot/util";
// Transform object keys and values
function transformObject<T extends Record<string, unknown>>(
obj: T,
keyTransform: (key: string) => string,
valueTransform: (value: unknown, key: string) => unknown
): Record<string, unknown> {
return Object.fromEntries(
objectEntries(obj).map(([key, value]) => [
keyTransform(String(key)),
valueTransform(value, String(key))
])
);
}
// Example: Convert API response to internal format
const apiResponse = {
"user_id": "123",
"full_name": "John Doe",
"email_address": "john@example.com",
"is_active": "true",
"created_at": "2023-01-01T00:00:00Z"
};
const internal = transformObject(
apiResponse,
key => key.replace(/_([a-z])/g, (_, letter) => letter.toUpperCase()), // snake_case to camelCase
(value, key) => {
if (key.includes('is_') && typeof value === 'string') {
return value === 'true'; // Convert string booleans
}
if (key.includes('_at') && typeof value === 'string') {
return new Date(value); // Convert date strings
}
return value;
}
);
console.log(internal);
// {
// userId: "123",
// fullName: "John Doe",
// emailAddress: "john@example.com",
// isActive: true,
// createdAt: Date object
// }Object Validation:
import { objectKeys, objectEntries } from "@polkadot/util";
// Validate object structure
function validateObjectStructure<T extends Record<string, unknown>>(
obj: unknown,
requiredKeys: (keyof T)[],
optionalKeys: (keyof T)[] = []
): obj is T {
if (!obj || typeof obj !== 'object') return false;
const keys = objectKeys(obj as Record<string, unknown>);
const allowedKeys = [...requiredKeys, ...optionalKeys];
// Check all required keys exist
const hasAllRequired = requiredKeys.every(key => keys.includes(key as string));
// Check no extra keys exist
const hasOnlyAllowed = keys.every(key => allowedKeys.includes(key as keyof T));
return hasAllRequired && hasOnlyAllowed;
}
interface User {
id: number;
name: string;
email?: string;
}
const validUser = { id: 123, name: "Alice", email: "alice@example.com" };
const invalidUser = { id: 123, extra: "field" }; // Missing required 'name'
console.log(validateObjectStructure<User>(validUser, ['id', 'name'], ['email'])); // true
console.log(validateObjectStructure<User>(invalidUser, ['id', 'name'], ['email'])); // falseInstall with Tessl CLI
npx tessl i tessl/npm-polkadot--util