Last active
September 12, 2023 18:23
-
-
Save eneajaho/33a30bcf217c28b89c95517c07b94266 to your computer and use it in GitHub Desktop.
Revisions
-
eneajaho revised this gist
Aug 18, 2023 . 1 changed file with 1 addition and 10 deletions.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -1,15 +1,6 @@ import { isSignal, Signal, untracked } from '@angular/core'; import { toObservable, toSignal } from '@angular/core/rxjs-interop'; import { combineLatest, distinctUntilChanged, from, isObservable, ObservableInput, of, OperatorFunction, take } from 'rxjs'; export type ObservableSignalInput<T> = ObservableInput<T> | Signal<T>; -
eneajaho created this gist
Aug 18, 2023 .There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -0,0 +1,79 @@ import { isSignal, Signal, untracked } from '@angular/core'; import { toObservable, toSignal } from '@angular/core/rxjs-interop'; import { combineLatest, distinctUntilChanged, from, isObservable, ObservableInput, of, OperatorFunction, take, } 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<Input extends readonly unknown[], Output = Input>( sources: readonly [...ObservableSignalInputTuple<Input>], operator?: OperatorFunction<Input, Output> ): Signal<Output>; export function computedFrom<Input extends object, Output = Input>( sources: ObservableSignalInputTuple<Input>, operator?: OperatorFunction<Input, Output> ): Signal<Output>; export function computedFrom( sources: any, operator?: OperatorFunction<any, any> ): Signal<any> { let { normalizedSources, initialValues } = Object.entries(sources).reduce( (acc, [keyOrIndex, source]) => { if (isSignal(source)) { acc.normalizedSources[keyOrIndex] = toObservable(source); acc.initialValues[keyOrIndex] = untracked(source); } else if (isObservable(source)) { acc.normalizedSources[keyOrIndex] = source.pipe(distinctUntilChanged()); source.pipe(take(1)).subscribe((attemptedSyncValue) => { if (acc.initialValues[keyOrIndex] !== null) { acc.initialValues[keyOrIndex] = attemptedSyncValue; } }); acc.initialValues[keyOrIndex] ??= null; } else { acc.normalizedSources[keyOrIndex] = from(source as any).pipe( distinctUntilChanged() ); acc.initialValues[keyOrIndex] = null; } return acc; }, { normalizedSources: Array.isArray(sources) ? [] : {}, initialValues: Array.isArray(sources) ? [] : {}, } as { normalizedSources: any; initialValues: any; } ); normalizedSources = combineLatest(normalizedSources); if (operator) { normalizedSources = normalizedSources.pipe(operator); operator(of(initialValues)) .pipe(take(1)) .subscribe((newInitialValues) => { initialValues = newInitialValues; }); } return toSignal(normalizedSources, { initialValue: initialValues }); }