---
# System prepended metadata

title: Aerial - towards "production ready"

---

# Aerial - towards "production ready"

This document lists / sumarizes Aerial's "areas of interest" for Pawel: semantics and public API surface that IMO needs discussion before embarking on the "production ready" implementation.

## Signal creation

Current API proposal:

```typescript!
const name = signal('Pawel');
```

Discussion:
* **"bike-shading" name**: ~~"state" might be interpreted something "bigger" than just a signal. How about `createSignal` or just `signal` ?~~ => renamed to `signal` for now, but we might revisit the name since there are 2 concepts being discussed here:
    * a concept / primitive of "value changing over time" + "changed / dirty notification" - this concept in itself doesn't indicate how the value is actually changed (mutable API);
    * a signal (above concept) + mutation functionality
* **notation of equality**: many signal libraries have the additional option of providing the "signal equality" function (usually defaulting to `Object.is`). This is a tricky therithory for aerial: 
    * our computed signals don't care about the equality (will propagete diry flag regardless of the actual value);
    * we want to work with mutable data structures so our default equality would need to compare primitive values only;
    * **Pawel's take**: skip the notation of equality for now.


## Reading signal's value

```typescript!
console.log(signal()); // it is just a getter!
```

Discussion:
* we might want to consider overriding `toString()` implementation as the default one from function will print stringified function body. 

## Signal types / branding

Current API proposal:

```typescript!
export type Signal<T> = () => T;

const SIGNAL = Symbol('SIGNAL');

export function isSignal<T>(value: unknown): value is () => T {
  return (value as any)[SIGNAL] === true;
}
```

Discussion:
* do we need separate types for read-only and read-write signals?
* do we need "runtime branding" of signals in the public API surface? 


## Signal change

Current API proposal:

```typescript!
signal.set('new value')
```

Discussion:
* do we need a specific type to denote a read / write signal?


## Signal update

Current API:

```typescript!
class MyCmp {
    counter = createState(0);
    
    increment() {
        this.counter.set(this.counter() + 1);
    }
}
```

Discussion:
* `this.counter.set(this.counter() + 1)` becomes verbose, options:
    * `this.counter.set(c => c + 1)` - passing a function is interpreted as "update function" - this might pose a problem where signal is supposed to hold the actual function as a value;
    * `this.counter.update(c => c + 1)` - pretty clear, but larger API surface;

## Non-reactive reads 

Most of the signal libraries have APIs to read signals value _without_ creating connection in the reactive graph (subscribing to future changes).

Current API proposal:

```typescript!
const baz = computed(foo() + peek(bar()))
```

In the above example the computation will be re-executed whenever `foo()` changes, but updating `bar()` value will _not_ trigger re-computation.

Discussion:
* ~~`nonReactiveRead` is probably too long as the name. How about: `nonReactive` or `untracked`? => `peek` is the current proposal~~

## Reads outside of the reactive context

Current Aerial implementation will throw whenever someone tries to _read_ a signal outside of a "reactive context" (`computed`, `effect` etc.). This requires a "reactive context" wrapper and:
* it is not clear to me how this would be represented in an Angualr application;
* might limit signals usage (read) in the 3rd party code and / or force depenency on Aerial (`nonReactiveRead`)


Check behaviour of other libraries:
* SolidJS - allows reads anywhere
* Preact - ?
* Vue - ? 

## Effects

Current API proposal:

```typescript!
const effectRef = effect(() => {
    console.log('changed: ', signal());
});
```

where `effectRef` has 2 methods:
* `schedule` - schedule effect execution (exact evaluation time depending on the scheduler abstraction);
* `destroy` - cleanup effect (so it stops executting, regardless of the dependencies change)

Effects will require bigger discussion around:
* types of effects and their execution timing in the application lifecycle;
* having `schedule` API (should people be allowed to "manually" schedule);
* cleanup 
* async effects
* ...



### API Proposal - Alex

```typescript=\
const disabled: SettableSignal = signal(true);

interface SettableSignal<T> extends Signal<T> {
  // replace the value with a different one (and mark dirty)
  set(newValue: T): void;
  
  // maybe update the value with a function (and mark dirty)
  // if the function is not passed, this just marks the signal as dirty
  // (presumably the value was mutated out of band)
  update(fn?: (value: T) => T): void;
}

const todoStore: Store<Todo[], ??> = createStore<Todo[]>(...);
                                              
// Stores are also signals, but have some custom API that's defined somehow.
type Store<Todo[], ??> = Signal<Todo[]> & ...;

// no need to distinguish the type here - just a reactive value with no extra API
const derived: Signal<boolean> = computed(value => !value);

// same here
const rxjsSignal: Signal<Thing> = useObservable(obs$);

// same here - signal-based inputs are just reactive values
@Input({signal: true})
myInput!: Signal<string>;
```

