# 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>;
```