> For the complete documentation index, see [llms.txt](https://docs.activejs.dev/activejs/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.activejs.dev/activejs/fundamentals/systems/custom-asyncsystem.md).

# 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.
