Key TypeScript and RxJS Concepts for Getting Started with Angular

So you've just been handed an Angular project and are trying to figure out how to get up to speed on Angular AND TypeScript AND RxJS. Take a deep breath, it's going to be ok! Here's a quick crash course to key TypeScript and RxJS concepts you need to know to get started ASAP.

April 29, 2019

So you’ve just been handed an Angular project and are trying to figure out how to get up to speed on Angular AND TypeScript AND RxJS. Take a deep breath, it’s going to be ok! Here’s a quick crash course to key TypeScript and RxJS concepts you need to know to get started ASAP:

TypeScript

Angular is written in TypeScript, and when using it’s classes and interfaces you’ll need a basic understanding of TypeScript concepts.

Public vs. Private Modifiers

What they are: A way to modify access to members and methods. Unspecified are public by default.

Why you care: Marking members and methods private makes them inaccessible from other classes.

Worth noting: Marking a member as public in a class constructor is a common Angular pattern you’ll see that is shorthand for setting that member on the class.

class Person {
  constructor(public name: string) {
  }
}

//same as
class Person {
  public name;
  constructor(name: string) {
    this.name = name;
  }
}

Types

What they are: A way to define what type your units of data should be. Types are boolean, number, string, array, tuple, enum, any, void, null, undefined, never.

Why you care: Assigning types helps us easily avoid buggy code at compile time. If you try to assign a value to a variable that doesn’t match it’s specified type, your TypeScript won’t compile.

Worth noting: TypeScript will attempt to infer Types when a type is not specified, from single values to complex objects.

let name: string;
name = 'Jennifer' //works!
name = 1337 // will error

let arrayOfStrings: string[];
let anotherArrayOfStrings: Array<string>;

arrayOfStrings.push('hi') //works
arrayOfStrings.push(27) //errors

Template Strings

What they are: No, this wasn’t a backtick copy-paste error! Template strings are a quick way to embed variables in strings using a backtick.

Why you care: They save you keystrokes!

Worth noting: They can have multiple lines.

let myName = 'Jennifer';
console.log(`Hello, ${myName}`);

let myHTMLTemplate = `<p>Hello, ${myName}</p>`

Interfaces

What they are: A way to define a contract for how an object, function, or class should look like.

Why you care: Not only can interfaces greatly aid development, but there are many useful Angular interfaces and knowing how to implement them will help you write less repeat code.

Worth noting: Classes implementing interfaces MUST implement all required methods and properties described by the interface. Also interfaces are NOT generated from the source code, they are just used at compile time.

interface Person {
  firstName: string
  lastName: string
  age?: number
}

let person1: Person;
person1 = {
  firstName: 'Jennifer',
  lastName: 'Wadella'
} //works

let person2: Person;
person2 = {
  name: 'Jennifer'
} //errors

Functions

What they are: Well, they’re functions, but in TypeScript we can give the functions a return type as well as set the types of the parameters.

Why you care: If you pass incorrect types to a function, pass more or less arguments than specified by the function, or try to return a value from a function with the incorrect type, TypeScript won’t compile.

Worth noting: Function parameters can be marked as optional using ?

function buildGreeting(name: string, phrase: string): string {
  return `${phrase}, ${name}`
}

These concepts will get you started working with TypeScript in an Angular app quickly, but to learn more in depth check out the Bitovi Academy TypeScript Guide!

RxJS

Observables

What they are: A publish/subscribe pattern that allows us to work with values that may change over time, for example, the value of a form input.

Why you care: Many Angular APIs rely on Observables, so getting familiar with them is a must. Not understanding observables can hang up many new Angular developers - for instance knowing that Observables are declarative and won’t execute publishing values until you subscribe to them.

Worth noting: Angular’s HTTPclient and Router both

import { Component, OnInit } from '@angular/core';
import { Observable } from 'rxjs';

@Component({
  selector: 'my-component',
  template: `<p>{{myDisplayValue}}</p>`,
  styleUrls: ['./app.component.less']
})
export class MyComponent implements OnInit {
  public myFakeObsData: Observable<string>;
  public mySubscription;
  public myDisplayValue;

  constructor() {
  }

  ngOnInit(): void {
    this.myFakeObsData = new Observable(observer => {
      setTimeout(() => {
        observer.next('hello');
      }, 1000);

      setTimeout(() => {
        observer.next('how are you');
      }, 2000);

      setTimeout(() => {
        observer.complete();
      }, 3000);
    });

    this.mySubscription = this.myFakeObsData.subscribe((val) => {
      this.myVal = val;
    });
  }
}

Subscriptions

What they are: How to get values that observables are emitting.

Why you care: This is how you’ll get your data! It should feel familiar if you’ve used promises/async/await previously.

Worth noting: You must unsubscribe to avoid memory leaks unless you’re using the async pipe in your markup.

import { Component, OnInit } from '@angular/core';
import { ObsService } from '../obs-service.service';
import { Observable, Subscription } from 'rxjs';

@Component({
  selector: 'my-component',
  template: `<p>{{myDisplayValue}}</p>`,
  styleUrls: ['./obs1.component.less']
})
export class MyComponent implements OnInit {
  $mySubscription: Subscription;
  myDisplayValue: number;

  constructor(public obsService: ObsService) { }

  ngOnInit() {
     this.$mySubscription = this.obsService.getObs().subscribe((val) => {
      console.log('new value', val);
      this.myDisplayValue = val;
    });
  }

  ngOnDestroy() {
    if(this.$mySubscription) {
      this.$mySubscription.unsubscribe();
    }
  }
}

Using the async pipe:

import { Component, OnInit } from '@angular/core';
import { ObsService } from '../obs-service.service';

@Component({
  selector: 'app-obs-async',
  template: `<p>{{myDisplayValue | async}}</p>`,
  styleUrls: ['./obs-async.component.less']
})
export class ObsAsyncComponent implements OnInit {
  public myDisplayValue;
  constructor(public obsService: ObsService) { }

  ngOnInit() {
    this.myDisplayValue = this.obsService.getObs();
  }

}

Operators

What they are: Ways to perform operations on values emitted by observables. Think of them as Lodash for streams.

Why you care: They are helpful to transform and map data.

Worth noting: The tap operator is a way to console log values without creating a new subscription. This is useful for debugging.

import { Component, OnInit } from '@angular/core';
import { Observable } from 'rxjs';
import { map, tap } from 'rxjs/operators';

@Component({
  selector: 'app-root',
  template: `<p>{{myVal | async}}</p>`,
  styleUrls: ['./app.component.less']
})
export class AppComponent implements OnInit {
  public myFakeObsData: Observable<string>;
  public mySubscription;
  public myVal;

  constructor() {
  }

  ngOnInit(): void {
    this.myFakeObsData = new Observable(observer => {
      setTimeout(() => {
        observer.next('hello');
      }, 1000);

      setTimeout(() => {
        observer.next('how are you');
      }, 2000);

      setTimeout(() => {
        observer.next('good I hope');
      }, 3000);

      setTimeout(() => {
        observer.complete();
      }, 4000);
    });

    const addName = map( (value) => value + ', Jennifer' );
    const addEnd = map( (value) => value + '!');

    let examplePipe1 = this.myFakeObsData.pipe( addName )
        .pipe( tap( (value) => console.log("val", value) ) );
    let examplePipe2 = examplePipe1.pipe( addEnd );

    this.myVal = examplePipe2;
  }
}

These concepts will get you started working with RxJS in an Angular app quickly, but to learn more in depth check out the Bitovi Academy RxJS Guide!