Skip to content

Instantly share code, notes, and snippets.

@eneajaho
Last active August 21, 2023 11:01
Show Gist options
  • Save eneajaho/53c0eca983c1800c4df9a5517bdb07a3 to your computer and use it in GitHub Desktop.
Save eneajaho/53c0eca983c1800c4df9a5517bdb07a3 to your computer and use it in GitHub Desktop.
Initial computedFrom impl
import { isSignal, signal, Signal } from '@angular/core';
import { toObservable, toSignal } from '@angular/core/rxjs-interop';
import { combineLatest, distinctUntilChanged, from, interval, isObservable, Observable, ObservableInput, of, OperatorFunction } from 'rxjs';
export type ObservableSignalInput<T> = ObservableInput<T> | Signal<T>;
/**
* So that we can have `fn([Observable<A>, Signal<B>]): Observable<[A, B]>`
*/
type ObservableSignalInputTuple<T> = {
[K in keyof T]: ObservableSignalInput<T[K]>;
};
export function computedFrom<R, A extends readonly unknown[]>(
sources: readonly [...ObservableSignalInputTuple<A>],
operator: OperatorFunction<A, R>
): Signal<R | undefined>;
export function computedFrom<R, A extends readonly unknown[]>(
sources: readonly [...ObservableSignalInputTuple<A>],
initialValue: R,
operator?: OperatorFunction<A, R>
): Signal<R>;
export function computedFrom<R, A extends readonly unknown[]>(
sources: readonly [...ObservableSignalInputTuple<A>],
initialValue?: R,
operator?: OperatorFunction<A, R>
): Signal<R | undefined>;
export function computedFrom<R, A extends readonly unknown[]>(
sources: readonly [...ObservableSignalInputTuple<A>],
initialValueOrOperator?: R | OperatorFunction<A, R>,
operator?: OperatorFunction<A, R>
): Signal<R> {
const obsSources = sources.map(x => {
const obs$ = sourceToObservable(x);
return obs$.pipe(distinctUntilChanged());
});
const initialValue =
typeof initialValueOrOperator === 'function' ? undefined : initialValueOrOperator;
const pipeOperators =
typeof initialValueOrOperator === 'function' ? initialValueOrOperator : operator;
const result$ = combineLatest(obsSources).pipe(
pipeOperators as unknown as OperatorFunction<any, R>
);
return toSignal(result$, { initialValue }) as Signal<R>;
}
function sourceToObservable<T>(source: ObservableSignalInput<T>): Observable<T> {
if (typeof source === 'function' && isSignal(source)) return toObservable(source);
if (isObservable(source)) return source;
return from(source);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment