@ayka/domistrukt
TypeScript icon, indicating that this package has built-in type declarations

2.0.0-rc.8 • Public • Published

@ayka/domistrukt

NPM Version NPM Version NPM License NPM Downloads

npm package minimized gzipped size NPM Unpacked Size

Tests and Code Quality CodeQL

Maintainability Test Coverage Mutation testing badge

Overview

@ayka/domistrukt is a lightweight TypeScript library that simplifies the creation of structured data objects. It offers a type-safe and flexible API for defining and initializing classes with custom properties and behaviors, making it easier to manage complex data structures in TypeScript projects.

Key Features

  • Type-safe Class Initialization: Ensures that classes are initialized with the correct types.
  • Custom Property Management: Allows creation and modification of properties with ease.
  • Versatile Input/Output Support: Handles different input and output types seamlessly.
  • Automatic Accessor Generation: Generates accessors for specified properties automatically.
  • Flexible Configuration: Offers various configuration options to suit different needs.
  • Helper Functions: Includes utilities for key selection, initializer creation, cloning, and property redefinition.

Table of Contents

Installation

Install @ayka/domistrukt using your preferred package manager:

npm install @ayka/domistrukt
yarn add @ayka/domistrukt
pnpm add @ayka/domistrukt

Getting Started

To begin using @ayka/domistrukt, follow these steps:

  1. Install the Library: Use npm, yarn, or pnpm as shown in the Installation section.
  2. Import Modules: Import the necessary modules in your TypeScript file.
import * as Strukt from '@ayka/domistrukt';

Usage

Basic Usage

type data = {
  valueString: string;
  valueNumber: number;
  valueBoolean: boolean;
};

class Example extends Strukt.init<data>() {}
const instance = new Example({
  valueString: '1',
  valueNumber: 1,
  valueBoolean: true,
});
console.log(instance);

Custom Create Function

class ExampleWithCreate extends Strukt.init<data>({
  create: (input) => ({ ...input, valueNumber: input.valueNumber + 1 }),
}) {}
const instanceWithCreate = new ExampleWithCreate({
  valueString: '1',
  valueNumber: 1,
  valueBoolean: true,
});
console.log(instanceWithCreate);

Handling Different Input and Output Types

class ExampleDifferentTypes extends Strukt.init<data, number>({
  create: (input) => ({
    valueNumber: input,
    valueString: '1',
    valueBoolean: true,
  }),
}) {}
const instanceDifferentTypes = new ExampleDifferentTypes(1);
console.log(instanceDifferentTypes);

Handling Undefined Input

class ExampleUndefinedInput extends Strukt.init<data, undefined>({
  create: () => ({
    valueNumber: 1,
    valueString: '1',
    valueBoolean: true,
  }),
}) {}
const instanceUndefinedInput = new ExampleUndefinedInput();
console.log(instanceUndefinedInput);

Creating Accessors for Properties

This feature is useful for hiding values from logging. By defining certain properties as accessors, which can help in preventing sensitive information from being exposed in logs.

class ExampleWithAccessors extends Strukt.init<data>({
  asAccessor: ['apiKey'],
}) {}

const instanceWithAccessors = new ExampleWithAccessors({
  someKey: 'someValue',
  apiKey: '1234567890',
});

console.log(instanceWithAccessors); // { someKey: 'someValue', apiKey: [Getter/Setter] }

Error Handling

The @ayka/domistrukt library provides robust error handling capabilities, allowing you to define both static and dynamic error classes. This section will guide you through creating and using these error classes effectively.

Static Error Classes

Static error classes in @ayka/domistrukt provide a way to define errors with consistent messages across all instances. These messages can be predefined and optionally overridden when needed.

Importing the Module

To use static error classes, first import the necessary module:

import * as Strukt from '@ayka/domistrukt';
Example 1: Static Error with Default Message

Create a static error class with a default message. This message will be used for all instances unless overridden.

class MyStaticError extends Strukt.staticError({
  message: 'A static error occurred',
}) {}

// Usage
throw new MyStaticError({ additionalInfo: 'Some context' });
// Output: Error with message "A static error occurred" and meta { additionalInfo: 'Some context' }
Example 2: Overriding the Default Message

You can override the default message when throwing the error, providing more context-specific information.

class MyOverriddenError extends Strukt.staticError({
  message: 'Default message',
}) {}

// Usage
throw new MyOverriddenError('Overridden message', {
  additionalInfo: 'Some context',
});
// Output: Error with message "Overridden message" and meta { additionalInfo: 'Some context' }
Example 3: Overriding Message in Constructor Parameter

You can also override the message directly in the constructor parameter, similar to the standard Error class.

class MyError extends Strukt.staticError({
  message: 'Default message',
}) {}

// Usage
const errorInstance = new MyError('Custom message', {
  additionalInfo: 'Some context',
});
throw errorInstance;
// Output: Error with message "Custom message" and meta { additionalInfo: 'Some context' }

Dynamic Error Classes

Dynamic error classes allow you to define error messages based on input data, making them ideal for conveying specific information about the context in which they occurred.

import * as Strukt from '@ayka/domistrukt';

type errorData = {
  errorCode: number;
  errorMessage: string;
};

class CustomErrorExample extends Strukt.error<errorData>({
  message: (data) => `Error ${data.errorCode}: ${data.errorMessage}`,
}) {}

try {
  throw new CustomErrorExample({ errorCode: 404, errorMessage: 'Not Found' });
} catch (error) {
  console.log(error.data.errorCode); // Output: 404
  console.error(error.message); // Output: Error 404: Not Found
}

Error Class with Input Transformation

You can define error classes that transform input data before using it to generate error messages. This is useful when the error message needs to be derived from processed data.

import * as Strukt from '@ayka/domistrukt';

type input = { value: number };
type output = {
  value: number;
  isEven: boolean;
};

class MyError extends Strukt.error<output, input>({
  create: (input: input): output => ({
    value: input.value,
    isEven: input.value % 2 === 0,
  }),
  message: (output: output) =>
    `${output.value} is ${output.isEven ? 'even' : 'odd'}`,
}) {}

const inputData = { value: 42 };
const error = new MyError(inputData);

console.log(error.message); // Output: "42 is even"
console.log(error.data); // Output: { value: 42, isEven: true }

API Reference

Strukt Module

init<output, input = output>(params?: config<input, output>): struktClass<input, output>

Creates a new class with structured initialization.

  • output: The type of the resulting instance.
  • input: The type of the input data (defaults to output if not specified).
  • params: Configuration options for initialization.
    • create: Function to transform input to output.
    • asAccessor: Array of keys to be defined as accessors.

Returns a class constructor that creates instances of type output from input of type input.

Error Module

staticError(params?: staticErrorConfig): staticErrorClass

Creates a static error class with a predefined message.

  • params.message: Static message or function to generate it.

Returns a new error class extending StruktErrorBase.

init<output, input = output>(params?: config<input, output>): errorClass<input, output>

Creates a custom error class with dynamic message generation.

  • output: The type of the error data after processing.
  • input: The type of the input data for the error.
  • params.message: Message or function to generate it.
  • params.create: Function to transform input to output data.

Returns a custom error class with the specified configuration.

Lib Module

selectKeys<t, key extends keyof t = keyof t>(target: t, keys: Iterable<key>): { [k in key]: t[k] }

Selects specified keys from a target object in a type-safe manner.

createInitFn<k extends klass>(klass: k): (...params: ConstructorParameters<k>) => InstanceType<k>

Creates a function that initializes an instance of a given class.

createUpdateFn<k extends klass1>(klass: k): (target: InstanceType<k>, patch: Partial<classInputType1<k>>) => InstanceType<k>

Creates a function that updates an instance of a given class with optional property overrides.

createCloneFn<k extends klass1>(klass: k): (target: InstanceType<k>) => InstanceType<k>

Creates a function that clones an instance of a given class.

redefinePropsAsAccessors<t, key extends keyof t>(target: t, props: Iterable<key>): t

Redefines specified properties of an object as accessors (getters and setters).

Contributing

Contributions are welcome! If you find any issues or have suggestions for improvements, please open an issue or submit a pull request.

License

This project is licensed under the MIT License.

Package Sidebar

Install

npm i @ayka/domistrukt

Weekly Downloads

10

Version

2.0.0-rc.8

License

MIT

Unpacked Size

135 kB

Total Files

8

Last publish

Collaborators

  • ayka