# Custom AsyncSystem

ActiveJS exposes an [AsyncSystemBase](https://api.activejs.dev/classes/asyncsystembase) class that can be used to create customized [AsyncSystem](/activejs/fundamentals/systems/asyncsystem.md) like [Systems](/activejs/fundamentals/systems/custom-asyncsystem.md).

One limitation of [AsyncSystem](/activejs/fundamentals/systems/asyncsystem.md) is that it doesn't let you change the type of [Units](/activejs/fundamentals/units.md) used by it. \
With [AsyncSystemBase](https://api.activejs.dev/classes/asyncsystembase) you can create your own AsyncSystem like Systems and use any type of Unit you want as `queryUnit`, `dataUnit` and `errorUnit`.

AsyncSystemBase can be utilized in two ways,

## 1. Direct Usage

Instead of creating an instance of [AsyncSystem](/activejs/fundamentals/systems/asyncsystem.md) where the [Units](/activejs/fundamentals/units.md) are created internally, you can create the Units yourself and pass them to the [AsyncSystemBase](https://api.activejs.dev/classes/asyncsystembase) directly.

```typescript
const customAsyncSystem = new AsyncSystemBase(
  new ListUnit<string>(), // queryUnit
  new DictUnit<{ a: number, b: string }>(), // dataUnit
  new GenericUnit<number>(), // errorUnit
  new BoolUnit(), // pendingUnit
  {clearErrorOnData: false} // config is optional
);

// extract the Units from the System
const {queryUnit, dataUnit, errorUnit, pendingUnit} = customAsyncSystem;

// confirm the type of Units
queryUnit instanceof ListUnit // true
dataUnit instanceof DictUnit // true
errorUnit instanceof GenericUnit // true
pendingUnit instanceof BoolUnit // true
```

## 2. Extend the AsyncSystemBase class

If you don't want to create Units every time you want to create a custom AsyncSystem, you can extend the base class and do the same thing that [AsyncSystem](/activejs/fundamentals/systems/asyncsystem.md) does, abstract away the Unit creation in the extended class and only accept typings through generics. This will allow you to be more efficient while still staying flexible.

**Example:** Create a custom AsyncSystem that uses [ListUnit](/activejs/fundamentals/units/listunit.md) as `queryUnit`, [DictUnit](/activejs/fundamentals/units/dictunit.md) as `dataUnit` and [GenericUnit](/activejs/fundamentals/units/genericunit.md) as `errorUnit`.

### Implementation:

```typescript
// accept the types for queryUnit, dataUnit and erroUnit as generics
export class CustomAsyncSystem<Query, Data, Error>

// extend the base class and pass the Units with types as generics
extends AsyncSystemBase<ListUnit<Query>, DictUnit<Data>, GenericUnit<Error>> {

  // accept config options optionally to pass them to the base class
  constructor(config?: AsyncSystemBaseConfig<Query, Data, Error>) {
 
    // create the Units and pass them to the base class along with the config
    super(
       new ListUnit(), 
       new DictUnit(),
       new GenericUnit(),
       new BoolUnit(),
       config
    );
 }
}
```

### Usage:

```typescript
type QueryType = number; // type for queryUnit's value
type DataType = string; // type for dataUnit's value
type ErrorType = {status: number, message: string}; // type for errorUnit's value

// initialize a CustomSyncSystem, pass the types as generics
const customSystem = new CustomAsyncSystem<QueryType, DataType, ErrorType>();
// that's it

// checking the types of Units
queryUnit instanceof ListUnit // true
dataUnit instanceof DictUnit // true
errorUnit instanceof GenericUnit // true
pendingUnit instanceof BoolUnit // true
```

## Notes

When using a custom AsyncSystem, directly or by extending, there are a few things that you should keep in mind, to get the expected results.

[AsyncSystem](/activejs/fundamentals/systems/asyncsystem.md) uses [GenericUnit](/activejs/fundamentals/units/genericunit.md) because it's very permissive in what it accepts as its value while other Units only allow a specific data type, this difference in behavior might cause a hung state, for example, if we use a [DictUnit](/activejs/fundamentals/units/dictunit.md) as the `dataUnit` and we try to dispatch an `array` value, it will get ignored and any observer expecting a new value wouldn't receive it. Additionally, `pendingUnit` wouldn't be updated automatically. (i.e. It'll stay `true` until successful data or error dispatch)

To mitigate this problem, when using a non-[GenericUnit](/activejs/fundamentals/units/genericunit.md) as a `dataUnit` or `errorUnit`, ensure that the value being dispatched is valid and will be dispatched. Every Unit has a `wouldDispatch` method for exactly this kind of scenario.


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://docs.activejs.dev/activejs/fundamentals/systems/custom-asyncsystem.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
