There's a repetitive bit of code that I find myself writing constantly, looks like this:
@Component({/* ... */})
public class SomeComponent {
private stateA$: Observable<TypeA> = // ... some RXJS
private stateB$: Observable<TypeB> = // ... some RXJS
private stateC$: Observable<TypeC> = // ... some RXJS
// Repetative code here
public componentState$ = combineLatest([
stateA$,
stateB$,
stateC$,
]).pipe(
map(([foo, bar, baz]) => ({
foo,
bar,
baz,
})
)
}
If it's not obvious, the reason for this is because it simplifies writing the component (*ngIf="componentState$ | async as state" on the parentmost div), and accessing state.bar seems a lot safer than state[1].
Since I write this so frequently, I've been trying to wrap it in a generic operator, but I can't seem to get the generics working so that the types are preserved. Here's the toObject() function:
function toObject<T extends string, U>(keys: T[], values: ReadonlyArray<U>) {
return keys.reduce(
(obj, key, index) => ({ ...obj, [key]: values[index] }),
{} as { [key in T]: typeof values[number] },
);
}
const test = toObjectHelper(['a', 'b', 'c'], [1, true, 'hello']);
Of course, the type of test not right.
// What my heart wants it to be:
{
a: number,
b: boolean,
c: string,
}
// What it is:
{
a: string | number | boolean;
b: string | number | boolean;
c: string | number | boolean;
}
I feel like what I need is something like:
// first key is typeof V[0], second key is typeof V[1], etc.
function toObjectHelper(/* ... */): { [ key in T]: U[indexOf key] } {
// ...
}
I've seen some solutions in the RXJS source (like the source for pipe()) where there is essentially an overload for any number of inputs, up to a maximum amount. Is that what I'd have to here, or is there a cleaner way?
Thanks