react-async-iterators
Version:
The magic of JavaScript async iterators in React ⛓️ 🧬 🔃
78 lines (77 loc) • 3.35 kB
TypeScript
import { type ReactAsyncIterable } from '../common/ReactAsyncIterable.js';
import { type DeasyncIterized } from '../common/DeasyncIterized.js';
import { type AsyncIterableSubject } from '../AsyncIterableSubject/index.js';
export { iterateFormatted };
/**
* A utility to inline-format an async iterable's values before passed into an other
* consuming component.
*
* Can be thought of as mapping an async iterable before being rendered/passed over in the same way
* you would commonly `.map(...)` an array before rendering/passing it over.
*
* @example
* ```tsx
* // Allows this:
*
* import { iterateFormatted } from 'react-async-iterators';
*
* function MyComponent(props) {
* return (
* <MyDropdown
* optionsIter={iterateFormatted(props.iter, ({ id, name }) => ({
* value: id,
* label: name,
* }))}
* />
* );
* }
*
* // ...instead of this:
*
* import { useMemo } from 'react';
*
* function MyComponent(props) {
* const dropdownOpts = useMemo( // `useMemo` with some pseudo third-party mapping helper `mapAsyncIter`:
* () =>
* mapAsyncIter(props.iter, ({ id, name }) => ({
* value: id,
* label: name,
* })),
* [props.iter]
* );
*
* return <MyDropdown optionsIter={dropdownOpts} />;
* }
* ```
*
* This utility should come handy in places when you need a formatted (or _"mapped"_) version of
* some existing async iterable before passing it as prop into an other component which consumes it
* and you rather have the formatting logic right at the place in code of passing the prop instead
* of having to perform the transformation using some `useMemo` call at the top of the component.
*
* The utility's method of operation is to be given a `source` and return from it a new transformed
* async iterable object, attaching it with some special metadata that tells library tools like
* {@link Iterate `<Iterate>`} and {@link useAsyncIter `useAsyncIter`} that the original base object
* is what the iteration process should be bound to instead of the given object. This way, the
* resulting formatted iterable may be recreated repeatedly without concerns of restarting the
* iteration process (as long as `source` is passed the same base iterable consistently).
*
* `source` may have a current value property (at `.value.current` - per the `AsyncIterableSubject`
* interface), in which case it will be formatted via `formatFn` in the same way like yielded values.
*
* If `source` is a plain value and not an async iterable, it will be passed into the given `formatFn`
* and returned on the spot.
*
* @template TIn The full type of the source input.
* @template TRes The type of values resulting after formatting.
*
* @param source Any async iterable or plain value.
* @param formatFn Function that performs formatting/mapping logic for each value of `source`.
*
* @returns a transformed async iterable emitting every value of `source` after formatting.
*/
declare function iterateFormatted<TIn, TRes>(source: TIn, formatFn: (value: DeasyncIterized<TIn> | (TIn extends AsyncIterableSubject<infer J> ? J : never), i: number) => TRes): ReactAsyncIterable<DeasyncIterized<TIn>, TRes> & (TIn extends AsyncIterableSubject<unknown> ? {
value: AsyncIterableSubject<TRes>['value'];
} : {
value: undefined;
});