I have a question about using combineLatest
with the startWith
operator
The code below works
const data_1$ = new Subject<string>();
const data_2$ = new Subject<number>();
viewModel$ = combineLatest([data_1$, data_2$])
.pipe(map([data_1, data_2]) => {
return { data_1, data_2 };
})
however now if I want to use startWith
operator
const data_1$ = new Subject<string>();
const data_2$ = new Subject<number>();
viewModel$ = combineLatest([data_1$, data_2$])
.pipe(
startWith(["hello", 1]),
map([data_1, data_2]) => {
return { data_1, data_2 };
})
The map
part will infer that data_1
and data_2
can be string | number
.
Can I get it to infer as the first example which doesn't use startWith
? I know about BehaviorSubject
and it could be used instead of startWith
but in my case I need to use startWith.
Starting from the official documentation, startWith
's typing is given by:
startWith<T, D>(...values: D[]): OperatorFunction<T, T | D>
In your case, you want to ensure that startWith
only returns something of the type [string, number]
.
The issue occurs because when you provide the array with ['hello',1]
it considers the type as (string|number)[]
. This is because in the generic declaration, only one type, D[]
is provided. Hence why it considers the type of ['hello',1]
to be (string|number)[]
, which fits D[]
.
To solve this, you can provide the typing explicitly with the use of the generic:
startWith<[string, number]>(['hello', 1])
The question then arises, why does map infer the argument type currently? Well the answer to this is also in the official typing of map:
map<T, R>(project: (value: T, index: number) => R, thisArg?: any): OperatorFunction<T, R>
In map
's case, it infers the type from the the provided value T
. Since there is no need to match any array casting, the value of [string, number]
is used instead.