Keyboard shortcuts

Press ← or → to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Chapter 3: TypeScript Primer

Angular is written in TypeScript, a superset of JavaScript that adds static typing and modern features. If you’re new to TypeScript, this chapter will give you just enough background to be productive in Angular.


3.1 What is TypeScript?

  • TypeScript = JavaScript + Types.
  • Compiles down to plain JavaScript (runs everywhere).
  • Adds features like interfaces, generics, enums, decorators.
  • Helps prevent bugs by catching errors at compile-time.

3.2 Basic Types

let isLoggedIn: boolean = true;
let age: number = 25;
let name: string = 'Alice';
let tags: string[] = ['angular', 'typescript'];
let user: [string, number] = ['Bob', 33]; // tuple

3.3 Functions

function add(a: number, b: number): number {
  return a + b;
}

const multiply = (a: number, b: number): number => a * b;
  • Return type can be inferred (often optional).
  • Parameters can be optional or have default values:
function greet(name: string = 'Guest'): string {
  return `Hello, ${name}`;
}

3.4 Interfaces

Interfaces define object shapes.

interface User {
  id: number;
  name: string;
  email?: string; // optional property
}

const user: User = { id: 1, name: 'Alice' };

3.5 Classes

Angular uses classes everywhere (components, services, etc.).

class Person {
  constructor(public name: string, private age: number) {}

  greet(): string {
    return `Hi, I'm ${this.name}`;
  }
}

const bob = new Person('Bob', 25);
console.log(bob.greet());

3.6 Generics

Generics allow reusable, type-safe code.

function identity<T>(value: T): T {
  return value;
}

let num = identity<number>(42); // num: number
let str = identity('Angular');  // str: string

3.7 Enums

Enums define a set of named constants.

enum Role {
  Admin,
  User,
  Guest
}

const currentRole: Role = Role.Admin;

3.8 Type Aliases & Union Types

type ID = number | string;

let userId: ID = 42;
userId = 'abc123'; // valid

3.9 Decorators

Angular uses decorators heavily (@Component, @Injectable, etc.).
A decorator adds metadata to classes.

function Log(constructor: Function) {
  console.log('Class decorated:', constructor.name);
}

@Log
class Demo {}
// Output: "Class decorated: Demo"

Great idea 🙌 — null safety and union types are crucial in TypeScript, especially since Angular templates often run into null | undefined values. Let’s expand the TypeScript Primer with a dedicated section on null safety and union types.


3.10 Null Safety and Strict Mode

By default, TypeScript in strict mode prevents you from using null or undefined unless explicitly allowed. This eliminates a whole class of runtime errors.

let name: string = 'Alice';
name = null;      // ❌ Error in strict mode
name = undefined; // ❌ Error

To allow null/undefined, you must explicitly declare it with union types:

let name: string | null = null;
let age: number | undefined = undefined;

3.11 TypeScript in Angular Context

While TypeScript is the foundation of Angular, not all features behave exactly the same in Angular templates. Here are some Angular-specific tips and “gotchas” you’ll encounter often.


The Elvis Operator (?.) in Templates

Already discussed, but let’s emphasize Angular usage:

<p>Email: {{ user?.profile?.email }}</p>
  • Prevents runtime errors when user or profile is null.
  • Very common when binding API-driven data that may not exist yet.

Non-Null Assertion Operator (!)

Sometimes you know a value won’t be null, but TypeScript can’t infer it. In Angular, this often happens with @Input() properties or template references.

@Component({
  selector: 'app-profile',
  standalone: true,
  template: `<p>{{ user!.name }}</p>`
})
export class ProfileComponent {
  @Input() user!: { name: string }; // “trust me, this will be set”
}

✅ Tells TypeScript: this will not be null.
⚠️ Use carefully — you can cause runtime errors if you’re wrong.


Type Assertions (as) in Templates

Angular templates allow as casting for better type narrowing:

<div *ngIf="user as u">
  <p>Hello {{ u.name }}</p>
</div>

Here:

  • user is checked for truthy value.
  • If true, it’s assigned to u with narrowed type.

This avoids repeating user?.name.


Strict Template Checking

With Angular’s strictTemplates option enabled (angularCompilerOptions.strictTemplates: true in tsconfig.json), the compiler will:

  • Catch invalid property bindings.
  • Ensure correct types in event handlers.
  • Detect missing async pipe unwraps.

Example:

<p>{{ user.age.toUpperCase() }}</p>

❌ Error: age is a number, not a string.

Strict templates = safer apps.


Async Pipe with Type Safety

Angular templates use the async pipe to unwrap Observables and Promises.

<p *ngIf="user$ | async as user">
  Hello {{ user.name }}
</p>
  • The as user syntax narrows the type inside the block.
  • No need for Elvis operator inside the block.

Angular Inputs and Null Safety

Inputs often need explicit null handling:

@Component({
  selector: 'app-avatar',
  standalone: true,
  template: `
    <img [src]="url ?? 'default.png'" />
  `
})
export class AvatarComponent {
  @Input() url: string | null = null;
}

Using ?? ensures there’s always a fallback.


Angular with Union Types

Union types model flexible inputs:

@Component({
  selector: 'app-status',
  standalone: true,
  template: `<p>Status: {{ status }}</p>`
})
export class StatusComponent {
  @Input() status: 'online' | 'offline' | 'busy' = 'offline';
}

✅ Type-safe: only accepts allowed values.
❌ Binding something else (<app-status status="sleeping">) → compile error.


3.12 Putting It Together

Angular templates are TypeScript-aware, but they extend it with:

  • ?. (safe navigation / Elvis operator).
  • ! (non-null assertion for inputs and bindings).
  • as (template type narrowing).
  • async pipe for Observables/Promises.
  • Strict template checking to enforce correctness.

3.13 Summary

  • TypeScript prevents null and undefined bugs with strict null checks.
  • Use string | null or number | undefined to allow nullable types.
  • Use optional chaining (?.) and nullish coalescing (??) for safety.
  • Union types let you model flexible values (string | number).
  • Type guards (typeof, in, instanceof) help narrow union types.
  • Literal unions let you model finite sets of allowed values.

👉 These features are heavily used in Angular:

  • Template bindings often deal with null | undefined.
  • Inputs and services may accept multiple types.
  • Strong typing makes your app safer and easier to maintain.