Во-первых, здорово, что вы хотите очистить плохой наблюдаемый код. Если бы я просто критиковал ваш метод, я бы сделал что-то вроде этого:

import { observable } from 'fp-ts-rxjs/lib/Observable';
import { sequenceS } from 'fp-ts/lib/Apply';
import { tap } from 'rxjs/operators';
// Setup Raw Observables
const welcomeMessage$ = this.http.get('some/api/welcomeMessage');
const apiCallTwo$ = this.http.get('some/api/chart');
const language$ = languageObs();
const dataRange$ = dateRangeObs();
const users$ = usersObs();
// Encapsulate Side Effects
const dateRangeSideEffect$ = dateRange$.pipe(
  tap(([startDate, endDate]) => { 
    this.startDate = startDate;
    this.endDate = endDate;
  })
);
const usersSideEffect$ = users$.pipe(
  tap(users => this.setUsers(users))
);
const apiCallTwoSideEffect$ = apiCallTwo$.pipe(
  tap(chart => this.chartData = chart)
);
// Construct Merged Observable
const mergedObs$ = sequenceS(observable)({
  welcomeMessage: welcomeMessage$,
  apiCallTwo: apiCallTwoSideEffect$,
  language: language$,
  dataRange: dateRangeSideEffect$
  users: usersSideEffect$
})
// Setup Subscription
const mySub = mergedObs$
  .subscribe(({ welcomeMessage, language }) => {
    this.setWelcomeMessage(welcomeMsg, lang);
    // all data aquired, wire-up everything
    this.launch();
  }
);

Но даже это проблематично, поскольку возможно, что language, dataRange и пользователи могут генерировать более одного раза! В будущем мы, возможно, захотим реагировать на изменения в users, dateRange или языке, вместо того, чтобы повторно запускать весь этот блок кода. В этом случае мы должны просто вернуть необработанные наблюдаемые как сами значения и распаковывать только тогда, когда нам нужно.

В ответ вы, вероятно, передадите в компонент все наблюдаемые, которые хотите наблюдать, а затем воспользуетесь несколькими перехватчиками, чтобы развернуть значения. Вот пример ловушки rxjs для такого случая (простите за машинописный текст, если вы не знакомы):

import { some, none, fromNullable } from 'fp-ts/lib/Option';
import { Observable } from 'rxjs'
import { useEffect, useState } from 'react'

const useRxjs = <T>(obs: Observable<T>, init?: T) => {
  const [state, setState] = useState(fromNullable(init));
  const [errorState, setErrorState] = useState(none);
  const [completeState, setCompleteState] = useState(false);
  
  useEffect(() => obs
    .subscribe(
      n => setState(some(n)),
      e => setErrorState(some(e)),
      () => setCompleteState(true),
    ).unsubscribe, [obs, init]);
  return [state, errorState, completeState];
}

В angular вы бы даже не подписались на свой класс компонента. Вы бы удалили побочные эффекты и сделали бы что-нибудь вроде:

import { observable } from 'fp-ts-rxjs/lib/Observable';
import { sequenceS } from 'fp-ts/lib/Apply';
import { tap } from 'rxjs/operators';
@Component({
  template: `
  <div *ngIf="myData$ | async as myData">
    {{ myData.welcomeMessage }}
    {{ myData.chart }}
    {{ myData.language }}
    {{ myData.dataRange }}
    {{ myData.users }}
  </div>
  `
})
export class MyComponent {
  readonly welcomeMessage$ = this.http.get('some/api/welcomeMessage');
  readonly chart$ = this.http.get('some/api/chart');
  readonly language$ = languageObs();
  readonly dataRange$ = dateRangeObs();
  readonly users$ = usersObs();
readonly myData$ = sequenceS(observable)({
    welcomeMessage: welcomeMessage$,
    chart: chart$,
    language: language$,
    dataRange: dateRange$
    users: users$
  })
}

И ваш компонент будет обновляться по мере изменения данных.

Надеюсь, это откроет вам глаза на некоторые другие закономерности. Извините, я не включил полный пример компонента React. Уже поздно, и я очень устал.